WWDC2004 Session 411
Transcript
Kind: captions Language: en good afternoon everybody welcome to session 4 11 cocoa tips and tricks so let's just jump right in I can get this worked there you go okay so today we're going to be showing you well they say we're going to have a bunch of Engineers from the cocoa frameworks team up on stage answering the sort of questions you might have and showing you how to put some cool features and some useful things into your applications we're going to show lots of source and lots of demos and just like everything else at the conference it's going to be available for download download on the ADC website all of the sakoda that you see today okay last year we showed you lots of cool features lots of useful things I hope we had a lot of fun and this year we've got even more things to show you and you can see there's a lot so let's just jump right in my name is Chuck vassula I'm an engineer on the cocoa frameworks team and let's take a look at the first question I have a table view and it doesn't know how to start though I'd like to add sorting can you tell me how hard that is well it turns out it's really pretty easy to do and what we need to do is two things we need to define which table columns are sortable how those table columns are sortable and then we need to provide the code that actually does sorting but at a table view is going to take care of everything else for us it's going to handle the UI handle clicks and in fact it's going to tell us when we need to sort now if you want to be you know even lazier nut and doing less glue code and less work you can just switch the bindings and this would all just work okay so how do we do our first job which is defining the sort ability of cable columns well what we need to do is provide a sort descriptor prototype for each column that we want to be sortable and in the search scripter prototype we're going to provide three bits of information we're going to say what the key is that we're sorting on what the initial sorting Direction is and what the selector is to use when comparing two objects during the sort now like many other things we can also set this an interface builder by inspecting the table column and setting the three attributes okay so our second job is to actually do the sorting as I said table view is kind enough to tell us when we need to update our sort ordering it's going to send us the table view colon short scriptures did change colon and the second parameter is going to be the old list of sort descriptors in case we know that we can do something more efficient by being given the old sort scriptures if we want the current sort descriptors we just turn around the table view and ask it for the sort descriptors now for some reason if you want to manage all the sorting yourself table you provide a routine to set the current list of sort descriptors and another interesting note is that the sort descriptors are persisted along with other information about table columns that are persisted so across reload a clock using across running of your application table do remember what the last or targeting was that the user using okay so now that we know when to sort we need to do the sorting and we're going to use some conveniences provided by NS array and its array knows how to take an array of sort descriptors which again we get from the table view and knows how to sort using the information in the sort descriptors one of the things is the key which is going to do the sorting out and finally you'll see at the bottom an example of how we might sort an array of things using a sort descriptor we're going to sort things in this array based on the first name value of each object okay before we go into this demo I wanted to do just a quick overview of what we're going to be looking at since what we're really going to be doing is an extending is extending an example that exists on the system already that example lives in developer examples apt it's called drag and drop outline view and what it does is display some hierarchical data and the data that it's managing is sort of a simple tree structure with nodes and each node has a pointer to some data so at this point I believe I want to go to the demos okay let's take a look at the application running and see what we're going to get in the end okay what you'd expect i click on a table column of sorts this actually in the existing demo it already knows how to sort based on the name column and in a second we'll see that it really was a hack and we're going to do it a better way and we're going to do it in a completely generic way now we're able to sort on each column okay so let's first take a look at our first job which is to set the sort ability of the table column we did this in interface builder and the first column is going to sort each object based on its name key and it's going to use compare colon to do its comparison and it's going to sort its initial direction as offending and we could have actually left compare colon off because that's the default if you specified null or nothing and then we'll see that we specified some values for the other columns the key will be is expandable to the second column and is a group for the last column okay for this example actually i'm going to show you the code a little bit of a different way than you've probably seen into all of the sessions i'm actually going to bring up file merge since as i said this is a demo on the system what i want to show you is what we've added to it so it lives in the original lives in developer examples app kit drag and drop outline view and we're going to compare it to this set of code okay and let's see what we've added so change the app application controller which is the data source of the outline view and there's one difference we've added the sort descriptors did change colon delegate method and what we're going to do is tell her our data to sort our tree data we're going to add a sort using descriptors method and then since we probably change the order of things we're going to tell the tale of you to reload the data and display it in its new order so let's take a look at simple tree node next which is a subclass of tree node and really all i want to show you here is that we removed our hack from before we used to sort things by forcing it to compare using the name key okay so that before we're sorting only in that column and it really was a hack it wasn't a good way to do things so let's do things a little cleaner more appropriate we're actually going to make it very generic we're going to put the sorting ability in our base class we've added a sort using descriptors routine to the tree node and take a look at the implementation so first we go and we tell our node children which is is an array we tell it to sort itself to reorder itself based on the sort descriptors and then we recurse and finally since we want to sort on keys in the data and we have a pointer to our data but we don't actually respond to all the methods in the data we're going to do a little trick and we're going to override value for undefined key so when we're trying to compare based on a key in the node which it doesn't respond to like the nodes don't respond to name it's going to go off to the data object and ask it for the value for name and so by doing this we're going to be able to sort based on keys in the data object and using those you know a small set of changes not many changes there were able to get sorting in our table view or our outline view in this case okay so if we could go back to slides please okay well that's great but you know your parents out there just going sorting is not boring I'm never going to sort anything no fun we make it a little more fun so could I add something like animation to the sorting so it's a little more Lizzie a little more fun to do a little bit more you know Mac os10 kind of sliding around fun style and certainly we can do that what we're going to do is make a subclass identify outline view the notes how it knows how to do all of this and what it's going to need to do is first take a snapshot of the location of all the items in the outline view before you do the reload and that's so that we can map index items from their old location to their new location so then the animation we're going to slide things from the old place to the new place so before we load will make a snapshot and after the data sorted by the data source what we're going to do is reload in a way such that we create an index mapping which shows where things went from and to and then we're going to do some custom drawing because well we're not drawing things at fixed locations and finally we're going to use NS animation to help us manage our timer and get the nice smooth curve values so we get a nice you know fun smooth animation ok so as I said we're going to make a subclass it's going to be called animating outline view and first we're going to add a method to it called well I like long lesson names for those you who know me it's called prepare for reload movement animation and this method is supposed to be called by the data source before it reads the data and this is a chance for the animating outline view to take a snapshot to take the snapshot location of where things currently live then after it sorts of data is going to call a new method that is on the bottom called reloaddata with movement animation and this is basically a new kind of reload that we're going to make which knows how to make the index mapping start up a timer which and is going to control and run our animation and of course it's also going to reload the data okay as I said we don't draw rose that fixed locations anymore and we're going to override draw row in clip wreck and what we're going to do is over time smoothly animate the rows at new locations and we're actually going to use a nice little trick by drawing these rows instead of into the table you're going to draw the rows into an image and then we're going to blit the images onto screen because we're going to be doing this lots and lots and lots of times very rapidly this means we only have to draw the roll one time and after that we can always use these images that we've cached away and we can get better performance okay so we're not drawing rose into a table view we're going to do a little trick and we're going to draw rose into an image so to do this we're going to create an image we're going to lock focus on it and then we're going to call tell-tale view go ahead and draw Rose like you normally did but se rule 3 where does it draw it probably draws it a coordinate of like and why of 51 and our image we don't want to make every single image for every single rose big is the table we just want to make it the height of a row so what we're going to do is trick the table view into drawing everything during animation at a y-coordinate of 20 and by doing this we're going to be able to draw into the it into the image and later on we're going to use it we're just going to blitz screen over and over and over okay so if we can go to the demo machine please now just so we see what we're going to get let's take a look at this one again before we start and well we've got sort it's not very fun yet let's cook the fun button and let's make some more data so it's a little more interesting and we've got some nice fun little animation going on all right so let's take a look at the code for this first thing on a do take a look at is the not that class is the animating outline view our new class it's a subclass of NS outline view it has some instance variables that help it manage the animation now this this example is a little more complex has a little bit more code than some of the other demos so I'm going to kind of breeze through it because you can get to look at it on your own and for the most part this is all some little lots of little details that need to be taken care of it's nothing too difficult and we've added an interface that our data source gets to use okay let's take a look at the actual code and jump down to prepare for reload animation and only if animation is enabled we're going to do a couple things first if we're animating before we happen to have some of the old stuff lying around we're going to throw it out start over and what we're going to do is sorry I guess want to jump down here we're going to create a dictionary which we're going to keep it as an instance variable it's something that's going to be used by the next reload and it's going to be the snapshot of the current order of all the items now if you have a very very very large outline view you can imagine this performance might not be great so I'm going to leave it as an exercise up to you guys to figure out more efficient way to do that kind of a trick and we mark some other information which is the current row selection so we can fix it up later okay so jumping ahead we have our reload data with movement animation and as I said it's a new kind of reload data it's going to do reloaddata and a couple of other things the first thing we want to do is compute our index mapping I'll let you guys take a look at how that's done offline if we're currently animating we finished the current animation we just bail and start over and then once we have an index mapping first we want to fix up the selection because things have moved to new locations so we're going to select the curt make sure the selection match event we're done with the data that we marked before so let's free it clear it out and finally jump ahead a little bit we retain our index mapping so that we can use it throughout the animation then we create a progress animation I'll go to that code in just a little bit that's a subclass of NS animation and what it basically will do is help us manage the timer and it's going to help us get the nice smooth curve value so that we don't have to know what function generates the nice smooth ramping and curve values and we're going to get those smooth values by specifying and its animation ease-in-out so it's going to ramp up and wrap down nicely we're going to use a non blocking mode we're going to create a place that we can store the images that we're going to use to draw during the animation and then we start the animation and it turns out that our our subclass of NS animation is going to tell us whenever we need to update and it's going to tell us by sending us this message progress animation current progress did change and when we get this while we're either at a point where we're done with the animation so we'll finish it or we're full will force a redisplay and when we redisplay i'm going to jump ahead a little we eventually end up getting into draw row and again what draw row is going to do is draw using an image so first thing it's going to do is figure out well where do I need to draw it's going to get the nice smooth curve values a little bit of math in this this routine that I have and it's going to figure out where the row should be at this point then we're going to find out well if it's not actually on screen let's just bail we don't want to draw if we haven't generated an image cache yet let's generate an image by the code I showed you in the slides we're going to create a name edge draw into it and then cash it away and finally we're going to just split the image onto the screen and again you hear you see in wrecked of Roe here's our trick to get the drawing to draw at a y origin of zero and the rest of the code I'm going to let you guys take a look at online these are just our help routines compute the index mapping figure out where we want to draw things and so on now let's take quick look at our animation subclass to subclass of ennis animation we add a new and knit method because we want to be able to specify something special which it doesn't normally have and that's a delegate and the delegate is the one that's going to get this message whenever the animation updates now if we take a look at the code for this it's really simple we have a cover for a net statue of the delegate and basically all it does so whenever the progress changes it tells the delegate that it needs to update the animation and that's it and it's nice because this class picture of all the little dirty details of managing a timer creating it getting its fire and it hides the details of how it computes the ease and ease out values and things like that alright and again once we have all that we've got our nice smooth animation and you'll see when you look at the code there's some other neat little tricks in there like we we try and make sure that we never you know if the table we had 10,000 things you don't want to animate something from 10,000 rows away you sort of want to clamp it to two times the visible height so that it's never too far away from visible so if you man away from really far away it wouldn't be on screen very long drink animation so there's some neat little tricks and I like that that I'll let you guys take a look at offline all right if we go back to the slides please okay well we've got some really cool fun animations but you know I'm sure this never happened anyone out there but the last minute we're bout ready to ship and H is they've changed their mind they want something they want to be in table view now not in an outline view so what are you going to do you're going to change everything to be a table view and you can change the data sources to use different data source AP is well here's a little trick what we're going to do is make an assault line view display looking more like a table view we're going to trick NS outline view to draw like a flat list and one advance to this is that you only have to deal with one delegate and data source you don't have to change anything in your nib and for those of you who want a unique identifier outlined views require unique identifiers per item per row but of course for some people that's a drawback so those are things you'll have to think about if you want to try this trick okay so we're going to trick NS outline view and what we're going to do is tell it set your indentation level to something like 0 don't draw with a big indent because that's one difference between outline view in table view and if it turns out that for some reason you're drawing a flat list but you have some hierarchical data well it would try and draw those turn down indicators and we don't want to draw those what we're going to do is over ID will display outline cell delegate message and when we get that we're going to effectively force the outline felt to be hidden and that's what you see down at the bottom if we could go back to the demo machine please I got a little overzealous and close things behind myself bring it up again now I'm actually not going to show the code for this because you just saw all of it on the slides other than some little helper things I've added and you'll see if you compare this to what already exists on the system for dragons are following views you compare it I've added the ability to change the data file that's being displayed and what it's going to do if it detects that there's no hierarchical data it's going to switch to using a flat list type display using the code that you saw on the slide and so all we do I know data file one happens to be a flat list i click that and it looks more like a table view and I didn't have to change anything in my nib and I didn't have to add any more code than what you just saw on the slide okay so if we go back to the slide please slide please thank you okay at this point I'd like to invite up on stage another one the cocoa frameworks engineers Tina Wong Tina [Applause] thank you very much Chuck once again my name is Tina pong and I work with Chuck on the app case so have you ever noticed that applications such as Xcode provide easy access to commonly used functions such as opening a file or creating a new project and they do this by having a menu in the dock well how can you add a dog menu to your application well the very easy way and basically no code method is at an ID to do this the drag menu out into your nib file and connect it to your applications doc menu outlet but there are times where in your dock menu you want the contents to very dynamically depending on the current state of your application and so to do this you have to actually create the dock menu in code and all you have to do is implement in your application delegate the application doc menu method and have that return your doc menus so to illustrate this I have a quick demo for you if I can go to demo to please so we're going to take a look at this first notice that when I well first of all I like to imagine that dot view is another application that you can get in your application developer applicate examples and if you went to the cocoa introduction talk i think all we showed you basically how you can create stop you but here we have in the doc menu red blue and green so we basically are allowing you to change the color of the dot in the menu however to illustrate a dynamic menu is kind of seemed silly to have read in your menu when your dog is currently Reds than just meaningless so we're going to change it so that if the dot is one of the current colors then take it out of the menu so say I select blue and now that's how the menu but if I were to change the color to something like maroon now I have all three options available so to take a look at the code and real quickly i'm going to change the indentation here so it looks a little better okay so taking a look at the code we've implemented the application doc menu method the first thing we do is we create a new menu and we're going to say the default colors here are red blue and green once we have that we're going to take a look at what the current color of the dot is and basically if it's red take read out the menu and the same thing goes for a blue and green and then for each one of the colors that remains we create a an NS menu item out of that color and set a note milky equivalent add the item to the menu and at the end return the menu we've just created and that's it if I can go back to slide please so that's great we can now change color easily in our dots using the menus but let's say in addition we want to have the ability to change the dot size as well now we could just add on top of red blue green the small medium and large size controls but then we're going to have a really cluttered doc menu so what we really want to do is have the ability so that when you hit the option key that red blue and green which is too small medium and large well again you can create alternate menu items in ID now ultimate many items are not unique to doc menus they apply to any ns menu you have but new and tiger is ultimate many items are also available for the doc so I'm sorry back to that previous slide the two general rule you have with dark alternate menu items is that the key equivalents have to be the same and the team modifiers have to be different so looking at how we would set this up an ID remember that you always want to work in pairs of menu items so in this case red is going to have the ultra menu items small and to do this I have on my on your left should be the red the inspector for the red menu item and on your right should be the small menu item we're going to first take a look at the key equivalents and notice here that they are indeed the same and having an empty string for a key equivalent counts then we take a look at the key modifiers and notice here that they are not unique so let's say for the small we're going to have the option key checked once you do that notice that the enable g as an alternate many items checkbox becomes enabled and all you have to do is check that and now small is the alternate menu item for rest and again you can do all of this in code by setting the key equivalent and the key modifier Mask using NS menu item ap is as well studying the alternate flag and I have a quick demo for you here as well so first taking a look at the running application we have to your red blue and green when I hit the option key I have small medium and large so when I hit here turns green with option Oh notice here that if there are only two colors available we remove the middle size always because it would be weird to have like small and medium so that's what we're trying to accomplish looking at the code and by the way when you look at your sample disk image all these are the same file they're just slightly reordered for demonstration purposes on stage so notice that in addition to creating the standard red blue and green colors for the alternates I have the available sizes small medium and large right here I have the code that basically says if I'm only displaying two color options remove that middle size and here's the interesting part so for every color I add and notice that once again the key equivalent is no I also create a menu item for the size with the same key equivalent and then i set the key equivalent modifier mass to be something different than the color and then I said to alternate flag and that's it then go back to slides please so that's fun but changing the color of the dots pretty boring and you know Chuck said OS 10 is all about fun with the animations so let's animate the dot color so that fades into the new color well again new in Tiger is NSU animation which is the only current public subclass of NS animation to create an NS view animation it takes an array of dictionaries with various properties set the important properties that we are going to focus on for this demonstration is the target key which should be the view or the window that you're trying to animate and did proper effect and in this case we're going to use a fade in effect once you set up your view animation all that's left to do is to run it so this is a very easy way for you to create animations in your app and I'll show you the demo of that so now rather than just having the color change when I took a different color it does one of those fun animations and the code for this is remarkably simple so we have the original dot view which is the color that we're actually changing but we want the color to actually have the original dot behind the dating in color so what we're going to do the trick it to do that is create a temporary dot view that has the same color origin and radius as the actual dot view and then we add it to our view hierarchy positioned above the actual dot next thing we do is create view animation with the temporary dot right here as the target and once again we're going to use the NSU animation fade in effect for the effect ii we create a view animation with with just that dictionary in it and then we're going to set the duration to one second just to make it last a little bit longer where's Chuck knew the non-blocking animation for the table view sorting we are going to run it in blocking mode so that the actual dots color doesn't change until the animation is complete and then we call start animation notice that by the time we reach this point here since we are running in blocking mode the animation is done and so it's okay for us to release animation and remove the temporary dot from the super view and that's it if i can go backslide fanimation is fun but what I really want is to be able to drag my view into a thought into into a file in a place that the finder but when I start that drag that location is unknown so how do i create the file well there are few possible solutions we could put the data onto the pasteboard as an NS PDF pase por types however that's going to leave a response the responsibility to the destination to actually write that to a file or we can create the file at some temporary location and once that drag is complete move that to the drop location or ideally we're going to delay the file creation until the drop occurs and to do this we use something called HFS file promises in NFU we have a method that allows you to drag promise file from racks etc and basically what you hand it here is an array of file types that you promise to create one to drop occurs once the drop occurs we get a call to name a promise files drop that destination here you're handed a URL containing the drop location and you'll easily create the file and that's all and to illustrate this so let's say I want I want to be able to drag this and have a dot in a PDF available in on my desktop and notice now that I open in preview and look I have my dot so you can send Christmas cards to all your friends with lots of dots you create and so looking at the code here in the mouse drag method here's where we promised the file type PDF and then once the drop occurs we implement the names of promise files dot the destination and again the drop to this nation is handed to you as a URL we have some clever code here that basically computes the file name so that if we don't overwrite a current existing file for those of you who've never seen this method this is an NS view method that basically allows you to create create a PDF out of any view so we create the data with that and notice here that I create the file URL and I route that file name to the drop destination and a right to that file what I return them this method is an array of the file names i have written and so that's great but let's let's say i have the Finder window and I traverse this whole hierarchy for where I want to place a file but notice that as soon as I click to drag I've now covered my Finder window and I no longer know where to drag to so what you really want is to delay that when they're ordering so that once I start a drag operation the application is not ordered front but if I click on the mouse up the window orders front so that way just really easy if I have my Finder window I can drag and not block that Finder window if I can go back to slides here so how do i prevent my application from blocking other windows during a drag operation and this is very simple in ennis window design a few method that you can override should delay window ordering for event and he returned yes the event the window will not be ordered until your mouth off event and now at this point i'd like to invite up the next presenter handsome soup Thank You Tina hi my name is handsome suit and I'm an engineering the cocoa group and for the next ten minutes I'd like to show you how you can use child windows and over the windows in your applications so let's say I have an application and I have a main application window and I want to create a secondary window actually go back to slides please well actually I'll just show you it's [Applause] yeah so I have a main window here and here's my auxiliary window and this is kind of useful for say I have a utility window or a tool palette that I want to be stuck to my main application window such that if i move the main window everything moves along with it so how do i do that back to slide please great thank you so we're going to do this by using something called a child linda we're going to make our auxiliary window a child window of our main window so we do this by very simply by calling a method on NS window called surprisingly addchild window ordered and we're going to give it one of two ordering modes above or below and so we can make our kai window either ordered above or below the main window and that's pretty much it that's all we need to do so now let's take a look at this in our actual code back to demolition ones so here we are we're going to start with the dot view application again that we all know and love and we have added a new controller class to our view and we're going to set up our child window in a wake from nib so we could have created our child window either in interface builder but today we're going to do it in code just to show you what it looks like and here we're going to set up the frame rectangle of our child window and then we're going to instantiate our child window here next we're going to tell the main window to add our child window and we're going to order it above the main limit now next after that we're going to order it above the main window again that seems a little redundant the reason why we're going to order it relative to the main window again is to work around a bug that I found when I was writing this demo involving I wasn't receiving mouse clicks correctly so what what turns out is we need to make this call in order to tell the app kit to properly register itself for event so without doing this the window doesn't the athlete doesn't know that the windows actually there so we're going to do that next we're going to draw a dot a dot view in our child window so we're going to create a new dot view and we're going to set the content view of our child winner to the dot view so as you can see going back to our groups going back to our you may have recompile it going back to our demo here that we can move the dot around and we can move the dot around the main window and I can move this child window anywhere I want so I can move over here and everything just works correctly it will always stay in the same relative position to the main window great so now I've got I don't know I've got two dots one in each window so given them my brain sometimes thinks like a three-year-old I want you connected us go back slide please so like any three-year-old who plays connect the dots I'm probably going to draw outside the line and in this case I have to draw outside lines because I'm going to be drawing a guideline in between the two windows from the dot in my main window to the dot in my travel una so I have to draw outside the bounds of my windows how the heck do I do that well the answer is you don't I'm going to I'm gonna have to fake it so I'm going to thank it by creating a new window a third window and I'm going to make that window invisible and this window is called an overlay window now a number of things to remember about over the windows an overlay window number one and most importantly is just another child Linda so it's exactly the same as my previous child window except for one thing well several things actually too we're going to overlay it above its parent window and three we're going to make its background transparent this is probably the most important thing we want we want it to both appear transparent invisible to the user and we want it to be transparent to events so that if you click anywhere on on the overlay window mouse clicks pass through to whatever is below it and lastly we want make the overly window borderless so that means we can't create an IV we have to do it in code so let's go back to the demo and take a look so we bring up our controller again and everything over here is the same code as before setting up our child window now we're going to set up a new window called an overlay window we're going to call it over the window now since an overly when it was just another child window if you take a close look the code is almost exactly the same as what we did when we set up our child window some differences one we we want to draw on top of both our previous two windows so we want the size of our overly window to be the union of the other two windows and next we're going to programmatically instantiate this and note we're going to give it a mask of NS window borderless borderless window mask then we're going to add it as a child window on top of our main window and here most importantly where these few lines were going to make the window chance the window background transparent so first we're going to set it a set opaque know so that events will pass through the window background and then we're going to set its background color to clear now we need to draw our guideline into some view in our overly window so what I've done is I've created a custom subclass the Venice view that I'm going to draw into and I'm not going to show that code to you now you can see that on the disk but we're going to instantiate that view and we're going to set it as a content view of our overlay window so if we run this let's see voila we have a line drawn in between our two windows and you can clearly see here that the whatevers will blow it is clearly showing through and I can move this around over here I can move the dot around everything to subspace correct everything they're just updates correctly so another thing i can do is i can resize this window and everything will update now a couple of things need to be done in order for this to work so one thing is if we move the child window where we want to tell the overlay view to redraw itself and if we resize the main window we wanted to we want to do the same thing another thing we need to do is we need to remember that since the overlay windows size is the union of these other two windows since its dependent on these other two winners so if I move this around or if I resize either these two windows I'm going to need also to tell the overlay window to update its size so we're going to do that in our controller again and we're going to implement to win to delegate methods on NS window window did move and window did resize we're going to listen to these notifications and if the if the windows the main window or the child window moves or resizes we're going to do want two are going to do two things we're going to tell the over label you to update itself and we're going to tell the overlay window to resize itself of course there's one little extra detail is when we only want to do this if the child window moves we don't want to do is the parent window moves and the reason for that is because when we move the power window the child window always moves along with it so we'd be doing it twice so we don't want to do that so here we're going to check explicitly to see if the window that's being moved is the child window so great everything just works we can move this around and can resize it at will and we've got our look nice little guide line drawn between these two dots alright that's slices so there's a number of other things that we can do now that we know how to use overly windows for instance we can draw controls and overlay windows this allows us to do interesting things such as draw controls on top of NS movie views and s opengl views as you know neither these two views can normally you can or you can't use normally embed controlled in them so this allows you to make it look like you've got buttons sitting on top of your movies or or on top of your 3d content so that about wraps up wraps it up for tribe windows and overly windows next I'd like to introduce Doug Davidson our resident text expert alright thank you handsome now let's go to the next question so this question here is about text completion now if you want the sort of completion behavior where the user is typing along your application and hits a key and is presented with a list of completions taken from the standard system dictionary then you have to do absolutely nothing that behavior is built into the text system but there is a reasonable chance that your application has a somewhat better idea than that of what the user might be trying to type so in that case you can customize this behavior and how can you do that well first and most obviously if you have a subclass of ennis textview then you have complete control over all aspects of the completion behavior if any of you were here last year in the text talk I % an example of this some of the methods you can use you can replace the completion behavior entirely by implementing your own version of complete or you are allowed to control the range and text of the user is presumed to be completed by implementing range for you to completion or you can supply a custom list of completions by overriding completions for partial word range etc and you can provide custom behavior when the completion is inserted back into the text by overriding insert completion for partial word range etc etc but that's not really what I want to talk about here today what I want to talk about today is what you can do if you're not a subclass of ennis text view but just a delegate of an NS text view and really you can do quite a lot there first and most obviously the delegate of the text view is given the opportunity to control and alter and change and completely control the list of completions that is presented to the user also the text views delegate is notified and given the opportunity well any time the user changes the test and the text views delegate is notified and given the opportunity to control whenever the user changes the selection in the text and if you put these together you can combine them to produce the number of interesting effects and if we can go over to demo number two I want to present a simple little example of that so let's just pull on it make this a little bigger now what a happier this application is what i like to call my Macintosh writers companion so when you're writing about the Macintosh you're always saying Maxis and mass that so when you're writing in this application let me make this a little bigger whenever you type Mac after a brief pause it helpfully an automatically offers to complete it to one of these standard forms macintosh mac OS michaelis 10 let me type mac wait there it is so how did we do that let's take a look at the code so the primary thing that we have here is a little timer and it's the timer that handles this brief pause and when the time requires it calls its method to completion and really all that does is to call complete on our text view where upon the completion behavior happens and we also have some methods here to start and stop the timer so when are we starting and stopping this timer well we're implementing those three text view delegate methods here that I told you about first of all one user makes any change to the text we take a look that change and we notice when they were typing that sea and on that case we start the timer it's pretty cute crew juristic but it works very well in this case there are plenty of more sophisticated things that you could do and have to make any other change we stopped the timer because we don't want to present the completion also if they make a change in the selection then we are going to stop the timer also but only if it is not the change in selection that occurs after the user inserts a piece of text because we already handled that case of above so we keep track of that and make sure we don't do it in that case and then when that timer fires after the brief pause and complete is called then the text view delegate gets called again to determine the list of completions to be presented and so we implement a delegate method for that and and there we just notice we check to see whether the string that we're being asked to complete is actually Mac and if it is then we offer to complete it with in this case Justice 6 list of macintosh mac OS mac OS 10 and that's all there is to it so let's go back to the slides and we can take a look at the next question so next question here has to do with mixing images and text and ourselves now when we think about a text cell normally what we think of is just plain text but what may not be entirely obvious is that you have the full power of the cocoa text system available to you whenever you use it so if you can display it and text edit you can display it in a cell or using string drawn and of course one of the things that you can do in TextEdit is to drag in images and have them displayed in line and the text so that's fine and texted it but how can you do that programmatically well programmatically images are a case of what a call attached file and the way that attached files of represented in a distributed string is as a special character the attachment character which has on it a special attribute the attachment attribute and the value of that attachment attribute is an instance of the class and it's text attachment and as text attachment models the contents of the attached file to do that it uses an NS file rapper but that's optional you don't absolutely have to have that if you don't need it and the other thing that it has to do is that it has to provide some visual representation to be displayed in line in the text and to do this naturally uses a cell and as text attachment cell and by default and it's text attachment will automatically generate an appropriate text attachment self but you don't have to let it do that if you know what you want the visual representation to be you can supply it you can use a completely custom and a technique statue itself subclass if you want to see an example of that come to the cocoa text talk on Friday section 437 I'll give an example that but what I'm going to talk about now is that you can use a text attachment cell and just set an arbitrary image on it to be displayed in line in the text and here are some of the relevant api's that sells and controls and so forth can have an attributive string value not just a plain string value you can create an interview directly from an attachment as a convenience method if you don't have to deal with the attachment character and attributes aboard you create a new text attachment with the foil wrapper if you have one you can query it for its attachment so you can set it the tasman cell and you can create this attachment cell with an image of your choosing if you like so if we can go back to demo to let me give a little example of that [Music] so that's right now what we have here very simple is nothing more than a list of colors in each color has a name and a little color swatch to show you what it is and perfectly ordinary except it what we have over here is just a stock one column table view no custom cell no custom anything is right directly out of interface builder the only code is written here is in the data source now let's take a look at that code I made this really simple all I have to provide the data is one array of colors and the parallel array of color name so I set up the beginning just fixed and static and so the number of rows in table view is always fix does that count as those arrays the really interesting code here is all in the table view object value column row so what I'm going to do here is create an appropriate attributed string that has in it both an image and the text so I get my color and the name of the color and I'm going to create an attachment I don't need a file robber here so i'll just use meal now i'll create a text attachment sell blank one and i'm going to create an image that why we use to be an image for my color swatch and then i'm going to create a mutable attributed string now when i created start off with i'll just have the color name string at this content that's not very interesting then what i want to do is to take on my text attachment and to insert it into the beginning of that string that tributed string so i'll replace the beginning of that attributed string with an attribute string created from my attachment very simple and then oh yeah somebody was actually asking about this on whatever mailing it's just today I wanted to shift the image down a little with respect to the text so they line up nicely and to do that I set that baseline offset on the character representing the attachment simple little shift moves it down so we line up nice and neatly now I need to make this image so i lock focus on my image that my color fill it up and get a color swatch then all I have to do is attach the image to the cell that's and find the cell for the attachment now everything is held on to by the attributed string so I can release the image still on the attachment return my attributed string and we're done that is it so that's our example we can go back to the slide and you can download this tonight use tomorrow and now i'm going to advise Chuck back up to wrap things hi again everybody so I hope you've enjoyed everything so far but we saved the best most exciting thing to last hopefully just blow you out of the water with this I'm going to show you some debugging tips well it's not very exciting maybe but it's something that everybody here has to deal with and our goal with this here is to show you some tips specific to cocoa which can help you in your daily work ok so what are we going to talk about for debugging wise we're going to show you some debug settings that you can set up that'll help you some gdb tips and we've got some ideas for helping you debug crashes alright so first what do I mean by debug default most of you probably know but I'm just going to review you can set defaults that apply either to specifically to an application or to the entire system and I have an example here which shows how to set the end of food default to some value and I've done in the command line using defaults right so this is a way to persistently set a default that will live forever until you get rid of it or if you want to just set it for particular run of the application there's two ways you can do it you can launch the application from the command line is specify dash and espoo default and give the value or you could do it in Xcode by finding the appropriate pain and setting the value ok and so what are some interesting defaults that might help you during debugging now the first thing I want to mention with all of these things these defaults these different tips we have maybe some methods we're going to suggest these are all meant strictly for debugging they're not strictly supported they may be documented somewhere maybe but the idea is that these are to help you for debugging only and help to you know save you some time but they should never be in a shipping application ok so and a show all views with that said sorry NSU all views can be set to yes or no and when you set it to yes it's going to show you something really ugly but the really ugly thing might actually end up being pretty useful for you what it's going to do is show you where everything in the view hierarchy loads it's going to outline everything with a different color and it might help you to discover that oh I've got a blank view covering my other view and that's why it's not why I don't see my view or you know they're not lining up right because other views are lined up in such a way it's useful thing I find the next thing I talk about is Anna show all drawing when you set that to yes it will sort of act like quartz debug now one those who use corpse debug one disadvantage courts debug it flashes the screen and yellow but it flashes the the buffer area that's being flushed to the screen and the buffer area is normally a coalesced area so if I just drew an area up here and I gern an area down here you know the whole area is going to get flushed screen and it might you know mistakenly convince you that you're drawing that entire region when you're really not so this is a little more targeted will help you see what draw rect code is actually being invoked and run one other note is that this works much better on tiger it doesn't work quite as well on Panther so it's just using it mostly on tiger the value can be set to yes or it can be set to an integer which specifies how long to delay between the flashing of yellow so on this example in the open panel here let's say I click on I guess media and when I click on media it's going to show me that Papa past the job because it knowledge to show media what instead of what used to and the new column that's being loaded is going to flash and that's what are you going to see it's going to flash delay flash it's going to be really slow but it's going to help you see exactly what's being drawn and it might help you discover that you're over dirtying areas and drawing things that don't need to be drawn to other interesting defaults I want to mention and it's less coal left view drawing I know it's a long name but I didn't put it in there what this will do is revert the coalescing of dirty Rex back to I guess pre Panther behavior and pre Panther what happened was if you dirty Dan area up here and your dirty an area down here Coco just happily coalesce them all together and told everything in that region to draw and in pants there a lot of hard work went in to making sure that we didn't do that and now we don't collect those wrecks together but because of that you may have been depending on that behavior and things that used to get drawn just to the coalescing may not be getting drawn so this might help you discover why your things not drawing if you're depending on that old behavior and then finally just a quick note about ms trace events at the bottom if you're not receiving Mouse events or keyboard events like you expect you could turn on trace vents and see what the cocoa event processing system is doing ok so how about some gdb tips so one thing we can do is we can peel an object now we're not making the object mad what we're doing is it's shorthand for print object I'm pretty sure print object and what it's going to do is print to the screen what it gets back by invoking the description method on your object now one thing that I don't know if this is actually declared in a public header and again this is strictly for debugging debugging there's a method called debug description I forgot to put down the slides with lowercase debug uppercase description you could override and provide a custom debug only description if you wanted to have peel print something different than it would normally print when you're doing like NS log of something ok some other interesting things are hidden parameters to methods this can be useful to know about there's every method has a self parameter which is not explicitly declared its hidden but it's there and there's an underscore CMD parameter which is the selector it's the name of the method a really interesting thing that this one of the interesting things about this that if I'm doing an NS log I get tired of doing NS log type up the whole method name I can just do NS log percent ass and I can say you know you see if the next step there and a string from selector so if I just want to print when i'm in a method i can just copy and paste lots of code and i don't have to keep typing the method name you'll find out in a second it's also interesting other places so if you want to print out the selector without doing p 0 you could actually print care star pet to find out it's actually i think it's a null-terminated but it's a string ok so some of these things become interesting when debugging crashes obviously message defend is the guy that tries to dispatch message and if it was just about ready to dispatch a method to your objects well those hidden parameters were all set up to be used and I didn't point out explicitly before and the slide that was there it said dollar r3 is the hidden argument self dollar for is the hidden arguments underscore CMD so if you wanted to figure out you know I crashed an obscene message send well it's not objected sees runtimes fault it was it's probably what probably was trying to happen was that it was about to dispatch a message to an object that was be allocated and what you can do is print care star of dollar are for and you can see what it was trying to dispatch or you can print the address of the object that was about to receive the message but of course if you try and pio the object at that point it's probably dead and it'll raise another exception but this could be useful when you're debugging to see what object was about to receive the message you know which object was dead so on and hopefully that's helpful normally well lots of times your crashes may be due to over releasing an object and one useful tip that may not be obvious that I just want to throw out is that you can use object a lock and turn on its retained release recording and you could use that to actually pair up your retains and releasing to see if somebody's releasing it that probably shouldn't be alright another idea for debugging crashes is to enable zombies all right this isn't something out of invasion of the body snatchers is actually useful feature that you can turn on in the command line and it's not a default like the other defaults we talked about it's an environment variable that you'll set and what you'll do is set the environment variable and a zombie enabled to yes and then what happens is for the most part the allocated objects don't go away they just get kept around in a state just enough that they can receive messages and raise errors and what's going to happen then is that when you try and message the dead object it's going to raise an exception like you see at the bottom in fact it's going to be nice enough to tell you where you could set a breakpoint to catch this now one thing to notice the note about this is that it works really well for kit level and gooey level object but it doesn't quite work so well for foundation object mostly for things that our toll-free bridged alright and another thing that I wanted to mention for debugging that I think it's i'm pretty sure it's new and tiger you can probably pretty easily find this out but it's a method called underscore subview subtree description and again remember these are methods for debugging only they've meant to help you out in debugging we don't want to have to support these if we want to change them for some reason to use them disclaimer so this is very useful because it prints information about an entire subtree into view hierarchy so friends for example this is a something i printed out from one of the earlier examples the animating outline view it's showing me that at the top level i have a scrollview which has a clip view of the sub view it has an animating out vietsub view and so on and there's a bunch of interesting information associate with it and don't don't worry about trying to scramble right down saw all this information really quick because this is also available on the on the download okay so the first bit of information it shows you to the frame and the bounds shows you the horizontal vertical resize springs and flags and it shows you a bunch of other flags again go ahead and look at the dmg okay again all this available on the dmg gotta