WWDC2003 Session 419
Transcript
Kind: captions Language: en good morning everybody welcome to session 419 cocoa user interface programming in depth for a session of the last day so hopefully you guys are wide awake if you're here at nine o'clock in the morning either you saw andreas when cuz presentation on two days ago the intro version of this or you still think this is coco performance techniques it's not we're going to go in-depth on some of the cool new ways of doing your interface and to talk about is Mark Petrelli thank you Jason so good morning Wednesday we introduced a lot of new technology that makes user interface programming much easier now today we're going to talk about the details in section 412 we let you know about all the new bindings and controllers technology we're introducing the goal is to automate user interface handling so you have to write much less code to provide some of the features you've been asking for of course we integrated support for it into interface builder and the whole goal of course is to make your development faster and easier and the effect on your application much less glue code so i love this screenshot on a big list of ib outlets just goes completely away so what i'm going to talk about today and general i'm going to talk about what it takes for your model objects to integrate into this system and the interfaces by which we allow that to happen our key value coding key value observing key value binding talked about a little bit about how the controller class to fit into this and there'll be some notes about performance at the end so the architecture that we try to adhere to while implementing all this is a classic model view controller for Coco model-view-controller means the view classes that we've always had a full set of user interface controls and everything model class is like NS document and nsdictionary makes a great generic model class and of course the model classes you provide now we're introducing three new controller classes and its array controller and its user defaults controller and then its objects controller we're using the key value coding system that's been in foundation since Mac OS 10 point and before actually we're introducing key value observing and Panther and key value binding which ties it all the other is how object relationships are established at nib loading times and things like that and in the interest of full disclosure at this point I should admit that on the WWDC disc NS array controllers their key value observing is mostly there but NS array controller doesn't use key value observing so a lot of what I'm going to talk about this a little bit idealized but it's definitely all going to be there in Panther and there's the lots of things on the wwcc or explain it and when I give examples today I'm just going to use the old classic sketch I updated sketch so that the graphics view supports binding and does observing things like that and it hooks up to one of the new array controllers and the draw document got updated a little bit to support key value coding key belly observing and I'll show you that so terminology there's some words that I'm going to be using that everybody uses but not everybody uses the same way so today when I see a property I mean an attribute a two and relationship or too many relationship by attribute I mean something simple a single immutable value like the fill color stroke width of a sketch graphic a 2-1 related object is a single object related to another it it's not an attribute it has properties of its own so if you know it'll have attributes an example is the sketch imageclass if you if you walk to we'll code the image is 21 related to the graphic I think that holds it and too many related objects are as the name implies collections of related objects for the graphics of a sketch document a sketch document has a collection of graphics so the first leg of the tripod on which all this is built is key value coding it's it's been around for a long long time we're making some changes to the implementations of the existing API we're adding new API and why do you care because if you're implementing custom model classes and you want them to work with this binding and work with controllers they have to be key value coding compliant and I'll show you what key value coding compliant means so key value coding is our system for giving access to object properties using a very generic API that identifies them by key and by keying we just need string for the most part a sketch graphic has around sorry sketch document has graphics identified by the word graphics and the individual graphics have properties like fill color and you just name the keys you know something programmer readable and these are the same keys that you saw it typed into the interface builder bindings inspector in Wednesday's demos so in the context of what we're talking about key value coding lets views get and set values and controllers and it lets controllers getting set values and model objects so the first semester of key value coding there's a bunch when we're going to go through like four of them today though they they're there what they would they serve about ninety percent of the time value for key return to value of the key property what's interesting about what it does is it actually uses the objective-c runtime to poke around in the class of the model objects which this message is sent and it invokes an accessor method whose name is typically just the same as the key so your model class is you get to write in a very natural way but this APL API allows clients to access them in a very generic way one of the features it does for you it converts scalar values like bullion's and integers and floats to NS numbers so that they can be passed up through the API and around to different parts easily so for example sketch graphic has a boolean attribute draws stroke and the accessor method is implemented in a totally natural way and it still works when value for key draws stroke is sent to that object and then this number is returned and an ass number is a little bit easier to pass around for the generic stuff than a boolean or an integer or flow would be something new we're adding to value for key for Panther is actually inspired by scripting and we're adding specific support to value for key for too many relationships you know collections of objects that aren't most easily stored in NS array a complicated example of this is in text storage its scripting support has a to many relationship called words and to have it pick it all apart and return an array of words every time somebody asks just for one of them isn't really that great of a thing or so we're we're adding a few more key value coding compliance methods so you'll have your choice you can either implement graphic in the example to sketch drawn ashman or you can implement two methods count of graphics and object and graphics at index to provide access to that relationship and so and whatever you choose the key value coding client the caller a value for key can't tell the difference it gets back and NS array key value coding puts the NS array together and the client that uses key value coding can send any NS array method to it including the methods that are implemented in categories and then try something new we added just by request was support for key value coding get accessor names that more closely match the conventions that you see in our API value for key not only looks for methods of the same name that looks for methods that begin with is so you know you can write still more natural code a brand new method for Panther is set value for key and as its name implies it sets the value of the keyed property it's a renaming of a method that's already in there called take value for key and typically we don't just go rename things and like in the kit this is actually in addition to the take value for key method that's already there but we consider the renaming we realize while we're working on this that key value codeine is going to get much more popular more widely used than it has been so we decided to clean up things like this so the default implementation does the equivalent of what value for key would would do it looks for a method whose name fits the pattern and invokes it so when you send an object set value for key fill color it will invoke a method named set fill color and just like value for key does it does NS number two scalar value conversion something that's been missing now we're adding to panther this can be very useful in the context of this UI programming is a new method named validate value for key error and its implementation is supposed to either return a value good enough for passing into set value for key or supposed to return an error and the reason this is separate from set value is because of separate validation rules from decisions about when to validate how to validate is always a model decision but when to value that validate is a UI decision so for truly reusable model objects keeping the separate is a good thing you might want to defer validation till the user hits the next puttan next button on a pain or something like that and the way you implement this is follows a typical KDC pattern you just have to name the method correctly and said I couldn't think of an example of this for sketch so I picked the zip code which I think people will probably be typing in a lot so and the method name just follows that pattern something really new for Panther is this method mutable array value for key and what it does is it returns an NS mutable array or something indistinguishable from one that contains too many related objects and the reason we need this is because you're not supposed to mutate the NS array that's returned my value for key when the key refers to Germany relationship so we wanted to support this concept of you know a client that's naive of the class to which is found being able to mutate sets of objects so we added this and the invoker of this method gets to send any NS mutable array message to the result again including things are implemented on categories so the user of this method really has total flexibility it's not limited to a specific API when manipulating the data but at the model class that provides the data doesn't have much responsibility it just has to implement two methods that corresponds to the two most primitive NS mutable array primitives insertion and removal so the client of key value coding gets to do all sorts of different things but thing that implements key value coding support for that key doesn't have much responsibility a concept that will be coming up a lot as I talk and shows up a lot in this UI technology is the concept of key path and for each one of the methods I just showed you there's a variant that takes a key path instead of just a key and these are actually probably invoked a little more often than the plane key methods and what's the key past a key path is just a dot separated list of keys and those methods that take keepass pick them apart at the right time and invoke accessor methods correctly so if you send to some object set value for key path image flip it'll get the image and it will effectively send set value for key to that image which boils down basically to the line you see on the bottom of just you know getting the image and calling set flipped so key value binding is in terms of key pass and key value observing is in terms of G path and our controllers use key pass for example and NS array controller republish a--'s the properties of whatever it's bound to it republish a--'s those properties you know of the selected objects and it does it using this key platform so you have to know about them but you don't have to do anything to implement them so if you're writing custom model objects like sketch graphics for example here's basically all you have to do to make those classes key value coding compliant you'd have to implement enough methods for value for key and set value for K and things like that to work so for each attribute or to one relationship you know single values you can just implement methods named the same as the key that you picked to identify that property and if it's a mutable property you have to implement a set method also if there's validation to be done you implement the validation method if there is no validation method that's fine validate value for key air just assumes there's no validation necessary for each to many relationship like the graphics in a sketch document you have your choice you can either implement a simple method with the same name as the relationship or you can implement a pair of methods whichever is most convenient in your situation and you know you can change it after the fact about having to go change other code for each to many relationship that can be mutated things going to be inserted removed a replacement it you just have to implement this pair of methods insert object and Keaton X and move on just from chea decks so the demo is you saw on Wednesday were great and they took advantage of the fact that nsdictionary is key value coding compliant so for simple model objects don't bother right in the class just use nsdictionary so you know it it responds to the set value for key and value for key method works fine it's and it's a very least and easy way to start prototyping and I think a lot of times are going to find out that your application is done before you run into the limitations of good old nsdictionary so possibly the the first limitation it will run into though is the fact that it doesn't do any validation of the values set value for key just goes in the head goes ahead and sets the value whether it's valid or not so the next thing that we're introducing panthers key value observing its all new api i'll talk about how to observe i'll explain why your model objects have to be key value observing compliant so that other objects can bind to them and i'll explain what you have to do to make your model classes kita observing component so what does key value observing do the summary is that it allows objects to be notified of changes to specific properties of other objects the notifications are very detailed and the context of this UI programming it lets views be notified of changes to values and controllers and it lets controllers be notified of changes to values and model objects an observer registers its interest in getting notifications using this method add observer for keypad options context this isn't part of an informal protocol and this object really does have an implementation of this but does everything you need we don't really expect this to be over in that often these messages are actually sent to the individual objects to be observed there's no observer Center that you know about or anything like that for this to be meaningful the receiver must be key by observing compliant as far as reference counting goes I think there's probably going to be a bunch of different situations as far as reference counting goes what's appropriate for the observer to observe the observed object or not so key value observing just stays out of the discussion it's API it doesn't cause any routines or releases well there'll be some standard things that people will do over and over again the star is retaining and releasing but the key value observing leaves everything very flexible and as you would expect if there's an ad observer method there's also or remove observer method so the first parameter is the observers the recipient of notifications about changes to the property identified by the keep at this observer must implement the NS key value observing informal protocol which is one method this one deserve value for key path of object change context and I'll talk about it a bit later and as again as an example of who's observing what they controls and sketches inspector panel that will show you in a bit will observe the selection property of an hour NS array controller to which is bound so the key path is just the keep a that identifies the property to be observed sticking to that example selection dot fill color and it can identify and attribute the two in a relationship or committee relationship you can not only observe simple values you can observe collections values and be told them things are inserted or removed or replaced he Valley observing supports two options right now we we definitely expect this list to grow in the future but right now they're just too new and old and these don't control when observing notifications are sent just what's in them when they are sent so new controls whether or not the observer notification has the value after the change and the old controls whether or not the observer notification contains the value from before the change that's causing the observer so I think in the the feedback after the session on Wednesday somebody asked about automatic undo support which is something we always think about and I think this old option will probably be a big piece of that comes around and the kind of there's a context parameter following a pattern that's common in a lot of cocoa API is something that you can pass in that will just be passed back to you at the right time and we think people probably use this for you know identifying the reason for the observation when one observer is observing a bunch of different things so the the notification method observed value for Q path of object change context is what sent to the observer for every change to the observed property and it's very generic key value observing doesn't care what you do when you observe this it's it's meant to be very low level and very generic so and the key path and the object are pretty much just the things bouncing back to you same thing with context change is a menace dictionary full of the information about what changed there are four possible entries into it the kind of change indexes for the change of the irony and new values and old values there are two basic kinds of observable change notification the first one is for simple setting when you know he value coding set value for key method is invoked and somebody's observing for that property this is the kind of changeable use setting if somebody's observing a to many relationship and it is something it's inserted or removed or replace you know one of these next three observer notifications will be sent and for example when might that happen when somebody uses that mutable array value for key method method and you know mutates the array that it gets back something like this will be sent to any observers and in the case of insertion removal replacement it provides the indexes of the objects that are inserted or removed to replace using the new index set class we're introducing them Panther it doesn't make sense for simple setting changes so it's not there then and the last two entries of the key value observing change notification our old values and new values and you know these aren't there if the observer didn't specify it wanted them when it registered as an observer so for simple changes settings these are just the old and new values of the property for insertions removals and replacements these are actually a raise of the objects that are inserted or move to replaced so how do you what does your model class have to do for these key value observer notifications be sent out when properties in your model class are changed well there's the pretty easy way in the really easy way this is a pretty easy way you just stepped us around the change with indications of will change value for key and did change on four key and in the case of too many that was four attributes into and relationships or too many relationships when collections of objects are being changed the methods you have to invoke are a little more detailed will change and yet specify removal replacement or insertion the relevant indexes and then again the key that identifies the to many relationship so that's not so bad but we don't even want to you know force you to have to write that much stuff into your model classes so we're introducing a feature called automatic key value observer notification and it's actually on by default so you don't even have to do anything to turn it on and what automatic qilai observer notification means is whenever any of those key value coding methods like set value for key is invoked that will cause an automatic key value observer notification to be sent out and not only that but indications of key value coding compliant methods result in observing notifications so not only the set value for key messages cause observer notifications for that key but soda implementations of the accessor methods for that property and not only do mutations of the result of mutable array value for key cause notifications but when any anybody sends an insert object in key it index or move object from key at index message to an observed container that will cause key value observer notifications so you don't have to sprinkle will change value for key and did change value for Keating all over your code if your model objects access their own values and each other's values consistent consistently through key value coding compliant method will do the rest you know simple set methods just keep using those you know you might already be using those and it'll just automatically work so and of course they're a couple situations where you can't go through those key value coding compliant methods and even when you're using automatic key key value observer notification the manual mode keeps working so key value binding it's the third lake leg of the tripod that all this sits on and it's brand new API and it's what ties it all together it's what allows the value of an object's property to be tied to the value of another object property and the safety our introducing provides plenty of flexibility so that objects can support binding options that we can't even anticipate and key value binding when it's being used that implies that typically key value coding and key value observing writing used to so this API is key value binding API is used at nib loading time typically you can be used with other times of course and views and controllers get hooked up to controllers and model objects key value observer or key value observers are registered with the things that they're observing UI controls at that point take responsibility for updating whatever they're bound to whenever the user manipulates the value that they're presenting and of course all the asset classes to which are adding bindings support do this so this is what the method looks like it's just buying to object with keep an options this is again sent at nib loading time you can use it at other times too for more complicated situations but for a while this will probably we don't expect too many uses of it you know other than nib loading time but it's there for you so and of course there's an unbonded tick so the parameters are the name of the binding and a lot of these look like key value coding keys but they don't necessarily have to be and for example NS control exposes a value binding and NS text field exposes and editable by meaning things like text color to the other parameters are you know what is being bound to the object that contains the proper to be bound to and the key path is a property and there's a dictionary that takes options so I think andreas covered most of these options pretty well on Wednesday which is to refresh your memory things like value transformers something that can manipulate the value for you know as part of more glue while things are moving around placeholders the marker values that come out of controllers for complicated selection situation become place holders that are presented in the UI and any options that are specific to the binding so controller classes there they're the first big clients of key value coding key value observing and key value binding there is an abstract superclass NS controller and three subclasses NS array controller object controller and user defaults controller so and its array controller is what you would typically bind a table view to now and NS array controllers have a to many relationship named arranged objects there's a set of objects to be presented to the user after any sorting or filtering or whatever it's done on the other side of the arrange controller you can bind it it's a ray relationship to the to many relationship of a model object in our example for example the graphics of a sketch document what the array controller we're using binds to so in key value observer notifications from the model object cause key value observer notifications to be sent to the table refers to the array controller then to the table you and the the array controller just doesn't pass them straight through it updates them to take things like sorting into account because that's what the table view is thinking about as arranged objects and it also keeps the selection up to date when inserted or removed objects I'm sorry when objects are are removed or inserted and make sure that the selection that's showing in the table view still make sense and in addition to binding an NS array controller to a relationship of model object you can just use the set content method that it publishes and let it manage the lifecycle of an array of objects you don't have to you don't have to bind it to anything you can just let it do all the work for simple situations so the first big feature that NS array controller has is selection management you can bind the selection indexes of a table view to an array controller selection indexes and when you do that and you've also bound the selection selection properties of an array controller to you know UI elements whenever the selection changes key value observer notifications are sent to the UI elements so for example a color well that's bound to an array controllers selection is notified whenever the in this example whenever the fill color of this directive selected graphics changes and that might happen either because the fill color of an individual graphic change or the set of selected graphics changed in all the different situations that would cause that to be updated in the UI msra controller isn't just for for binding it provides real API of its own you know big set of methods you get to call and just the selection of them NS array controller has built-in support for user friendly selection behavior a few flags like avoids empty selection for when that's appropriate in the table view preserve selection so things are are being inserted and removed around the selection the selection statesville and selects inserted objects from and that's the right you I behavior and for situations where the array controller is being manipulated by some other code of your own you can get it all the things like the selection index is using methods like that selection indexes and add and remove the other big feature that NS array controller supports right now is sorting so you can bind the sort descriptors of a table view to the sort descriptors of an array controller so as the users clicking in the the table column headers to change the sort order the table view tells the controller that the list of sort descriptors has changed and when it does that and this array controller actually does the sorting and sends out key value observer notifications for the array and ranged objects relationship so that was an NS array controller and its object controller is also there and its name implies it controlled a single object instead of an array so why is it useful to bind a UI control to an object controller it's because you combine an object controller is something that might be you know coming and going it will observe a to one relationship and another object and I it's those clever things like handling the situations where that two men are that I'm sorry that two one related object disappears or the type of it means that the bound to property is no longer applicable so in general and object controller serves the purpose of generating these marker objects that you heard about our Wednesday that get converted to placeholder objects that show up in you I even in simple situations so in just as with NS array controller for this object controller it has a set content method so you can just let it own what's being presented and the third new controller is NS user defaults controller and we saw demonstrations that on Wednesday and what you do is you buying the values of you I controllers to the value of the user defaults control you know some sub property of it that's the key for which you know you get to pick the name so not only can you do that but you can observe and its user default controller so other parts of your program that want to know immediately when the preferences change can just register themselves with key value observers of those properties and NS user default controller also supports handy support for setting the initial values of preferences you know the factory defaults and shared user defaults controller is easy to get to an IV you saw it being picked from the the pulldown menu in the bindings inspector on Wednesday so let me show you some of this code I'm talking about so let's say that sketch was so useful that it was worth packaging up and making sure that it was properly reusable the first thing we would do in doing that is adding binding support to its graphic view and here's a simple implementation of the key value binding method that I told you about this sketch graphic view supports two binding names one is graphics the list of graphics to be presented in the view and selection indexes just you know that which graphics are selected so in the implementation is pretty simple all it does is it just stores a pointer to the container of the graphics that's being passed in the keep a that was specified and then it starts observing that container of graphics so it wants both graphics that are being inserted and graphics that are being removed so it can update the display and I'm sorry I move removed while that's happening and the context that specifies just so it can identify why it's getting these observer notifications is just one of a handful you know simple and it really just needs them for identification purposes and for selection indexes it does a similar thing it records the information about what the graphic view is bound to and then adds itself as an observer and then it updates the display so sketches draw a document for it to allow things to bind to it it has to be key value coding and key value observing compliant for this graphics relationship that it publishes this is all it takes to do to be both key value coding and key value observing compliant for that relationship just something that returns an array of the graphics and the method that handles insertion and in this case it still has to do its own undo support and in addition to doing the actual insertion that also tells the graphic what document it's been added to that's actually part of sketches scripting support for individual graphics individual graphics also have to be key value observing compliance so that the sketch graphic view can observe them can be told when they're changed so it knows to update the screen the first one I'll show you here is set fill color and I didn't have to change this at all this is already key value coding compliant and because we're using automatic key value observer notification it's already kto compliant so no changes necessary for this one for set stroke line lift it does a little more the line width of the sketch graphic effects how large the graphic is on the screen so it just manually says when the line width changes the drawing bounds change and actually there's another feature that's going to be in panthers called set Keys trigger change notifications for dependent key a mouthful but this is what you can use to indicate things like the drawing bound of the sketch graphic depends on the line with so this will change value for key and did change value for key it won't even be necessary in this situation though should leave it in just so you can see what it looks like so I just run this and it's sketch you know sketch that's all so it has inspector panel and I'll select them all so as you change things that just works so and I'll show you the code for the inspector panel in a second and changing things is automatically updated on the screen so the code for the inspector panel I think you can see this coming I'll show you some of the bindings in the nib this is pretty neat I be gives you a nice summary of what's going on with the bindings so the checkbox here for controlling whether or not the graphic is filled it's just bound to the selection draws fill of an array controller the fill colors bound the selection dot fill color of an array controller and actually it's really not appropriate to leave that enabled when that check box is not checked so you can bind the enabled binding of the color well to selection draws film so and so on so because of all the binding support in the inspector panel and because you know and it's a raid controllers taking care of everything for you here is the source code for inspector controller which is no longer part of the project I got to take all of it out so this is not actually built into the project anymore so how many lines of code got to go away because of that finding support and inspect repent we won't count a copyright notice so about 250 lines so if they go completely away so the last thing I'll talk about today is performance some of what we're doing to make sure that the new technology is fast enough to use and some performance notes about being key value coding compliant and Q value observing component so as I mentioned observation info is actually associated with each individual observed object and it might sound expensive you might imagine oh no that means that there's going to twice as many objects in my system each object and then the observation info for each object and no that won't be the case we're actually taking great care to make sure that when multiple model objects are being observed in the same way same set of observers same key seems like that the memory that's allocated to record that observation is shared between the individual observed objects key-value coatings performance has always been very important and we're making sure we don't ruin it with key value observing so set value for key has a certain cost to it and are making sure that cost isn't going to go up inappropriately when somebody is observing that cube for that model object so and the general rule we're following is that we're providing good default implementations for everything but we're open to optimization but we're leaving things open to optimization for specific cases which I'll show you one piece of advice for you value for key don't override it there's a bunch of performance tricks we can play as far as caching objective-c runtime info goes but all those tricks are effectively defeated if value for key is overridden so in general just stick to the pattern of implementing you know key value coding compliant accessor methods so I mentioned that we added a support for implementing key value coding compliant methods of the form counts of key and object and key at index those are required if you're using that pattern of giving access to relationship if measurement says it's worth it you can also implement a method whose name follows this pattern get key range so those first two methods correspond roughly to the primitive of NS array and this next method corresponds pretty much to another NS array method that you can override for mutable to many relationships you have to implement these insert object and remove object methods you can also implement a replace message if it makes a difference in your too many relationships case so that's just two optional key value coding compliant methods we plan on adding a bunch more in the future as we get more experience with this seeing how people are using it and you know see the the performance issues that need to be dealt with so and for example we you know we might add more optional key value coding compliant methods that lets you insert and remove ranges or work with the new and its index set class that's being introduced in Panthers so and whatever we do though we don't intend to you know change the list of methods that's required to be key value coding compliant as far as using key value coding goes the advice is don't over use it so if you're converting code making it more generic letting it support bindings and you're converting implementations of simple methods to uses of value for key and mutable array value for key that might be worth measuring when you're all done with that these methods are pretty fast considering what they do but they will always be more expensive than a simple objective c message dispatch so you should check that when you're using value for key in getting an array back or using mutable array value for key and getting mutable array back what we're suggesting for now is try to use it just like you would a normal NS array or NS mutable ring our intent is that the performance characteristics will be pretty much the same as a real an iterator and it's mutable array so if then when that's not the case we want to hear about it and if you see optimization needs to be done try and keep that in the model code and you know where it will be more reusable as far as efficient key value observing compliance goes there's a pair of methods that you get to override if you need to and I think typically you won't but they're called set observation info and observation info so when large numbers of objects are being observed you know the observation info is actually stored separately from the object associated with a hash table and that should be good for most of the you know most of the time but there may be situations where it's not and when it's not we just want you to give us four bytes of instance variable space and let us put the observation info there and in general with key value observing take advantage of the fact that these observation notifications are our super fine granularity it just doesn't say that the object changed it says that this property of the object changed so you know don't don't cause Q value observer notifications to be sent out when nothing is actually changing and on the other side of it don't observe not necessarily so that the asset views to which binding support are being added take care not to observe gratuitously the best example of this is table view when a table views role objects are bound to too many relationship in a container for example in an NS array controllers arranged objects which will be typical if the table view if there's like you know hundred thousand rows and the in the table it doesn't observe a hundred thousand objects it just observes the 50 that are visible at any one time and we're taking care to make sure that adding and removing one object as an observer of another is is fast enough to make that feasible so there isn't any noticeable overhead while you're scrolling a table view caused by the facts of this table view is d registering itself as an observer the objects as the scroll off and registering itself as an observer in six tall on so one more pair of methods I haven't told you about yet it's the bulk variance of AD observer and remove observer so the same set of parameters as the ad observer in the new observer I've already shown you but it's sent to an nsarray and it takes an index set identifying the objects to which key value observer should be added or removed so and in general you know there's a little bit of work that has to be done when one object adds itself as an observer of another with these methods that little bit of work is only done once basically the observed objects you just told you know here's your observation and if I'll hold on to it for me so that's pretty much it on Wednesday we introduced great new technology to make user interface programming much easier and today we talked about what it takes for your custom model objects to hook into that so and it basically boils down to being key value coding compliant and ki doli observing compliant and we work pretty hard to make sure that that's going to be fast and easy for you it so I hope you all give what is on the wwc see it a try it should work pretty well for you and and we hook you a right great custom apps with this thang thanks mark let's see okay so here's the roadmap obviously this is make much sense since it's Friday but fortunately there are dvds that you'll be all getting so make sure you look at those dvds when you get them check out the intro Coco the cocoa update sessions and so on we do have a couple of things still coming up today we have the tips and tricks for 24 sort of your reward for staying through the entire week some really cool stuff in there and of course so what's new for Coco tech some really great stuff that we've added to the text engine okie dokie there we go so John Glenn geez the person you want to talk to if you've got some information feedback what have you on all the coca cells that you've seen at the show you have general API suggestions they should go to Coco dash feedback at group that apple com those go directly to the cocoa engineering team and if you have code level questions they should come to my team develop technical support where I have to help you if you need more information we've got no documentation [Applause] but feel free to check the headers we will we will have documentation for Panzer you