Mac • 1:12:08
The Cocoa frameworks give you high-level access to the underlying power of Mac OS X. Get an overview of the latest Snow Leopard advances in key Cocoa frameworks such as Foundation and Application Kit. This session will orient you for the other Cocoa sessions that cover these technologies in further detail.
Speakers: Ali Ozer, Kevin Perry
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
My name is Ali Ozer. I'm the Manager of the Cocoa Frameworks team at Apple. And Kevin Perry, who's my colleague in the team, will be joining us shortly. So what are we talking about today? We will cover changes in Cocoa since Leopard. And there's a lot of changes we've done since last WWDC, so we're going to give special coverage to those as well. And we will also provide pointers to other sessions. There are a lot of topics.
In addition to stuff we added to Cocoa, there's advancements in Objective-C, Garbage Collection and other frameworks such as Core Data and Core Location and so on. We're not going to cover those, and just give pointers to them whenever we can. And in addition I would like to point out this is not what's new in Cocoa Touch. There is another session for that. This is primarily focused on Cocoa on the Desktop. There is a session at 10:30, What's New in Cocoa Touch. So here are the topics, sort of the rough outlines of the talk. And this is just a very rough high-level outline.
There a lot of individual topics, we'll go into throughout the talk. So first I want to talk about 64-Bit. Now, we talked about 64-Bit before in many sessions, so this is going to be fairly brief. As you know, we've been making good strides towards 64-Bit over the last few releases.
And in 10.6 almost all the applications on the system are now 64-Bit. Now, back in 2006 in the 64-Bit overview session, which I gave, here is we did some prophecy and we said 64-Bit applications. We prophesied that they were not going to be. They were not here in Leopard, but post-Leopard they would likely be here some day. And back then, we were looking forward, thinking maybe, you know, five years, whatever. Well, it's now just three years later and 64-Bit apps are here.
The system, the center of gravity of the system has shifted towards 64-Bit apps. Most of the time the users are just running 64-Bit apps right now. What this means is if you have a 32-bit-only a2pplication it's time to consider moving it to 64-Bit apps. Because just like we said back then, you know, you don't want to be the only one left with a 16-bit app in a 32-bit world.2 That's the same way it is really with 64-Bit, so some day is here.
Now, what does 64-Bit mean ford Cocoa? It's actually on the surface a very small change. We just introduced three new types. These are 64-Bit versions of the types commonly used in our APIs, and their alternate definitions for them for 64-Bit. So if you're writing a brand new 64-Bit application, or if you're even writing an iPhone application, just use these types and you'll be fine. If you have an existing application, we have a script help you convert your application. You, here's the script. It's called ConvertCocoa64, and the one on Snow Leopard is newer than the one on Leopard, by the way. To run it you'd make a copy of your sources.
You just run the script on every source file in your application. And then you go ahead and fire FileMerge or your favorite diffing tool and basically confirm all the changes because there might be some that you don't like. Now, if you already run the script and converted your application to 64-Bit, then you're wondering do I need to run this script as well? The answer is no. This script just does a few things a little better, but these are already things you probably would have fixed or found. It basically generates far less warnings, for instance, which makes the conversion process a lot easier.
So that's about it as far as 64-Bit. There is a great document, the 64-Bit Transitidon Guide. You can type this into Google or just go to this URL and it will tell you all about what 64-Bit means. What the conversion script does and various other issues you need to watch out for. Now, as you know, Carbon. The high-level Carbon APIs are not available in 64-Bit. And one thing we've done in Cocoa is try to fill in the various holes that we had in Cocoa APIs where you might have fallen to Carbon to get something done.
In some cases, these new APIs are just one-to-one replacements of functions with new methods. In other cases, we introduced brand new extractions in Cocoa to satisfy this need. So I'll start off with NSApplication, which now has a new API setPresentationOption that lets you control the system user interface elements. So this means if your application, for instance, wants to run without the Dock Visible, or your application wants to disable the ForceQuit menu, etc., you can do this with this API.
Now, note that the PresentationOption's API which returns your current presentation options, and currentSystemPresentationOptions which returns to you what the current, no matter whatever app's set at, what the current setting is, these are key value observable so you can actually find out even when another application changes the setting. Now, the options you might pass to this include these.
You can, for instance, cause the Dock to be hidden or cause it to be AutoHidden, the same with the menu. You can disable AppleMenu, ProcessSwitching, ForceQuit, and etc. Elements like that. Now, there's a tech note 2062, which goes into detail about how these options interact. It's in terms of the system UI mode API which is the old Carbon API that's being replaced here. And we'll update the tech note at some point to talk about this new API as well. We have some enhancements in NSWindow, again providing API that was previously available through Carbon. You can now disable server-side dragging, so basically this makes a window non-movable.
And once you set this you can choose to move the window yourself. Because as you know in Cocoa windows are typically moved on the server, which means windows can be moved even if your application is busy or not responding. But this will prevent that and you can do whatever you want. You can now hit-test any screen location to find out what window there is. Note that this API returns an NSInteger rather than an NSWindow.
And this way we can return any window, not just windows belonging to your application. So this is a window number that can track any window in any application. And finally, we can return to you the window numbers of all visible windows, whether they are in your application or any application. And this returns an NSArray of NSNumbers. And the options you can provide are justYourApplication or allApplications, and justThisSpace or allSpaces.
NSRunningApplication is a brand new class, which replaces the processes API from Carbon. This is a pretty straightforward API. It returns to you properties of applications that are currently running on the system. You can find out things whether, like whether the apps are hidden or active. What their localized name is. What their icon is and so on.
And so you can do a lot of things that involve running applications with this API. Note that some of the properties here are also KVO-observable so you can observe them change. A running application, in addition to returning properties of applications lets you hide, terminate, even forceTerminate if you wish, and activate running applications with these APIs here. And there's ways to get back running applications. For instance, you can ask for your current application.
You can ask for a running application, which corresponds to a UNIX process ID. Or you can get back an array of running applications that share a bundle identifier. And the reason for returns on the array here of course is you can have many applications that share the same bundle identifier.
There is also one more way to get running applications, and that's to ask NSWorkSpace for the array of all running applications. And note that this array here is also KVO-observable, so you can see this list change. Speaking of NSWorkspace, there's a lot of new APIs on this Workspace. I'll just touch upon one now. You can display a Spotlight search results window. So this is equivalent to a user bringing up a Finder window and typing in a search string.
The search string you give will be used to bring up this Finder window. The user can then go ahead and fine-tune the query. Note that this corresponds to the Carbon API HISearchWindowShow if you might have used that before. Along the same lines, we have some NSView API to bring up the Dictionary application. You can either use the first API here to bring up your basic Dictionary application that uses the Dictionary or various other, you know, Thesaurus and etc. for a given word.
Or you can use the second API to bring up a, customize the way the window is shown. For instance, it can be shown on top of your document and so on. Now, note that the second argument here, showDefinitionforAttributedString with four arguments, also takes a block as an argument which lets you fine tune the positioning, and we'll talk about blocks shortly. Another area where we've made a lot of changes is NSPasteboard. You might know that Carbon has this concept of multiple items in its NSPasteboard APIs, while in Cocoa that feature has always been limited to specialized cases like file names, keyboard type.
Well, NSPasteboard now supports multiple items. In addition, there's a more, a new and more general API. It's in terms of UTIs, we have these two protocols, PasteboardWriting and PasteboardReading, which many AppKit classes implement and you can also implement them yourselves. We also have a Pasteboarditem class, which is a generic container to let you participate in the new Pasteboard APIs more easily. Now, I'm not going to say much more about Pasteboard here because there is a half a session dedicated to it.
And this session is Thursday afternoon at 2:00. The other half of this session is Services. You might know Services. It's always been in the first menu or the second menu, in your Application Menu. It's been, the Services features has been with us since 10.0, in fact, even before 10.0. What we've done to Services now is make them more discoverable, make them context sensitive, and also allow the user to customize them.
So here's what the Services menu looks like in 10.6. If you've seen the Services menu before you'll notice that it's got icons. The capitalization's better. It no longer has nested sub-menus. And also note that there is an item here, Services Preferences. If selected will let the user enable or disable individual services that they wish to use, so it's fairly handy.
Again, this is part of the Pasteboard and Services talk Thursday at 2:00. Bunch of changes in NSMenu. There's actually a lot of changes. Just highlight three. You can now display a menu as a popup without having to resort to Carbon APIs, which always involve some underhanded dealing that I don't want to hear about.
You can allow a delegate to control the menu location. Basically return a brand new rect where the menu appears. And finally, you can stop the menu from tracking at any point. So if you are doing something special with the menu and you want the menu to just go away. No animation.
Nothing. You can call this method, cancelTrackingWithoutAnimation. The last topic I'm going to cover in this section is NSEvent. We now have methods to let you get user preference settings, doubleClickInterval, keyRepeatDelay and so on. Pretty straightforward. And we have two other methods that let you get the mouse state and the keyboard state. So basically, what modifier flags are down or what mouse buttons are pressed. Now, note that these are class methods, not instance methods, so you can ask these questions at any time in your application and get the current state. You don't have to have a current NSEvent.
The other event enhancement is Event Monitoring. You now have the ability to monitor events coming in to your application, or in fact any application. This first API here, addLocalMonitorForEventsMatchingMask, lets you install a monitor that sees every event coming into your application. And you can also affect them. Meaning, you can either let the event pass through or substitute a new event.
Or in fact, just stop the event altogether by returning nil, and that's sort of the ultimate form of censorship, if you wish. The other method is the global one, addGlobalMonitor. This one is similar, except it doesn't let you affect events. You can only observe them. Now, note that these return IDs.
When you are. When you do not want to monitor anymore, you just call the removeMonitor and pass that ID in there. There is some limitations to the usage of these things. For instance, if your application's in the tracking loop, the events won't be seen by this, by the local monitor.
In addition, events going to, say, secureTextFields will not be visible here, and that's probably a good thing. There is an events talk, which will cover these and many other topics. That's tomorrow afternoon at 3:30, User Events in Cocoa. Now, note that here as well these two methods have handlers, which take block arguments. And as you can see, we're using block arguments more and more in Cocoa APIs.
And I want to talk about blocks right now and then I'll move on to concurrency. Blocks are snippets of code that capture lexical scope. If you were at the sessions yesterday, you saw some examples of them. But I really want to make blocks concrete for you so that, you know, when you see a block you can easily read it and it becomes second nature. So let me just give you a few examples. Here's a block example. We're declaring a variable called myBlock, and you can recognize that this is a block because there's a caret instead of a *.
If it this was a function variable it would have been a *. So the variable's called myBlock. It's a block that returns an int, and it takes a single argument, which is also an int. Now, note that this is the body of the block. Here we're actually creating a block, a literal block, and assigning it to the new variable. This is the whole block. A literal block.
The single argument we've given it a name of num here, and here is that actual body of the block, which could be arbitrarily complicated. In this case, we're just using the incoming parameter num, and we're multiplying it by multiplier, which is a value that's captured off the stack In this case 7. So that's captured.
It's a constant in this case. And of course, if you were to run something like, say, myBlock(3), you would get back the result of 21. Now we will cover blocks in good detail in a talk tomorrow. Yes, tomorrow afternoon at 5:00. Objective-C and Garbage Collection Advancements. But I do want to talk about them a bit more.
Here is another place where you might see blocks quite often. This method enumerates lines using blocks, which is a new method on NSString. This is the method of taking a block argument. The block returns nothing, so it's void. It takes two arguments, an NSString and a Boolean *. And the name of the parameter is block.
So this API basically enumerates NSString and calls your block with every line in the string. And you can stop the enumeration by setting *stop=yes. There's a bunch of related APIs, and I'm not going to talk about these right now. In NSString and that's an attributed string because we do have a text processing talk, which is Friday morning at 9:00 a.m. That will go into more details about this and plenty more. The last example of blocks is one that's used in the typedef.
Here we're creating a typedef called Comparator. It's a block that returns a comparison result, so less than, greater then, equal to. And it takes two arguments, the objects being compared. Let me show you a concrete example of an API that uses this. NSArray has an API called sortedArrayUsingComparator.
And as you can imagine it sorts to array given the Comparator. And here is an actual usage. You might call, for instance, myArray sortedArrayUsingComparator and pass a block, which in this case simply calls localizedStandardCompare on the two arguments. This is also a new method we've added. Now, as I said the block here could be arbitrarily complicated.
It can do all sorts of stuff. In this case, it just happens to compare to two arguments with this alternative method. Now, I'm going to talk at this point a bit about block naming. As you know, in Cocoa getting APIs right is very important to us. In addition, being able to communicate our conventions, our guidelines so that our APIs are predictable, and you yourselves can also create APIs, which are consistent, those are very important factors for us.
Now block is a challenging name, because when used as a verb it means something totally different than what we use as a noun. For instance, if you're a casual reader of some code and you came across myArray block, instead of returning a block that might seem like something that blocks execution of the array.
Or similarly, window beginSheetblock:, while it was intending to take a block argument you might think it's just an argument that takes yes or no to block the sheet. So instead of block, we want to use more descriptive names. More descriptive terms in our method names. And several that we've come up with include Handler, Provider, Test, Comparator. Handler for something that just, like a delegate almost handles something. Provider for something that takes some arguments and returns another argument. Test is something that is a predicate, returns yes or no. And Comparator you've already seen.
Now, we will still use block in our APIs, but only in generic cases where it's not easy to describe what the block does. So let's go back to our collections example, NSArray. Here's the sorting method we already saw. We have two other categories of functionality that use blocks in our collections.
One is Enumeration, and the other one is Searching. Now, note in the Searching one you're passing basically a test And for every, this enumerates to the array, and for every item that returns yes from your test, it will go ahead and put in an index set and return all the indexes that match this test.
Now, in addition to these three methods we have a lot of other variants. We have versions of these for the other collections. Dictionary, Set, and IndexSet. In addition, we have variance of these that take options, and if appropriate a subset to work on so you can choose to integrate only a part of the array for instance.
So there are many other methods along these lines. I'm not going to show you those now in detail. But I do want to talk about concurrency, so let's move on to the topic of concurrency. So we saw Enumeration, Searching and Sorting and you can now do those concurrently.
The way you do that would be to provide an option. Either EnumerationConcurrent or SortConcurrent. And here's what the sort case might look like. You would call sortedArrayWithOptions and you would pass SortConcurrent and you would pass in your Comparator. So what this means is that the provided block may be invoked concurrently, so it should be thread-safe. The other thing to note here is that the overall operation is still synchronous, meaning the method will not return until it's done. Let me give you an analogy for this.
Imagine you go to the carwash. You drop off your car. Typically you would wait until your car is washed, and that's a synchronous operation there. Now, you might take your car into the carwash and one person might wash your car. Well, with this concurrent option it's as if you took your car to the carwash and 12 people descend on your car and all wash it, and clearly your car's going to be washed faster. Now, also note that if you took your car to the carwash and 200 people descended on it, that'd be a big mess because they probably would just wreck the car.
And, of course, it's responsible given NSArray and the Grand Central Dispatch that it uses to make sure that sort of disaster doesn't happen. But again, your car. You will wait there till your car is finished, except the concurrency will let it happen much more quickly. The other thing to note here is that if you are enumerating concurrently you are no longer enumerating in order.
You're not going from 0 to end. You're going to be all over the map, and that's obvious with something to keep in mind. The other concurrency topic is NSOperation and NSOperationQueue. These are clearly important pieces of the concurrency story in Cocoa. Simon talked about these yesterday. The big change here is that these classes have been reimplemented to be on top of Grand Central Dispatch. Now, note here the sort of the power of Cocoa Extraction.
These classes were available to you in Leopard and a lot of people are using them. In Snow Leopard, we have reimplemented them on top of this new facility, which means they are faster. They can handle a lot more load. In addition, they now share in the same pool of resources that Grand Central Dispatch does, which of course is great because it gives the system a better idea of how to balance things. However, for the most part your code is not affected at all. Your code, which works on 10.5, will work under 10.6. It's just faster, better, and so on. Now, we also took the advantage to add a bunch of new APIs.
NSOperations can now have thread priorities, and you can specify a completion block to be executed when the operation is done. NSOperationQueue now allows you add multiple operations and optionally wait till they're done. You can also add a block as an operation, and we also have an explicit class for this, NSBlockOperation, which lets you add a block in an operation and tweak various other parameters for it. NSNotificationCenter has also one new method to allow concurrency. This method here now allows observers to get notifications concurrently. So just like before, you're adding an observer specifying a notification name and object to filter on.
Let me show you the Leopard version of this API. You are specifying the name and object, but in the Leopard version you would provide an observer and a selector. So the selector to get called on you observer. In the Snow Leopard version these have been replaced by a queue and a block to execute on that queue. If you provide nil as your queue, you basically get the Leopard behavior for this.
Now, the good thing about this API is that it's fairly, it's very compatible from a posting point of view. There is no change to the notification posting code. Because what happens here is all the posting is done, but all the observers have to be done until this method is done, I mean, until the notification posting is done. So in that way this is sort of analogous to that carwash example I gave you before. Until, you know, everything might happen concurrently but, you know, the execution will not continue until it's all done.
Because if we did sort of open the floodgates and make it asynchronous, you can imagine that a windowWillResize notification would get delivered before window did resize and that would cause a lot of fun things. The last concurrency topic I want to touch on is Concurrent Drawing. NSView subclasses can now opt-in to Concurrent Drawing just by setting setCanDrawConcurrentlyYes.
What this means is when a hierarchy of views is being drawn in Display or displayAsNeeded, views that have specified this property can be drawn concurrently with other views. Now again, Display or displayAsNeeded is blocked until drawing is done. So again, this remains fairly compatible to existing practices. You just have to make sure you've used Drawing is thread-safe. Also note that because of this approach, in most cases the thread-safety demands on your model are not changed. You know, if there was cases where you couldn't change your model in other threads, those still apply.
Now, these and the other topics I touched upon will be covered in more depth tomorrow morning at 9:00 a.m. in Concurrent Programming in Cocoa. Now, there is one more concurrency topic to talk about, and that's Concurrent Document Opening, which the TextSet application now does. And to talk about this and some other new Snow Leopard features we are showcasing and TextEdit, I'd like to invite Kevin Perry on stage.
[ Clapping ]
Thank you, Ali. Concurrent Document Opening is just one of the enhancements that we made for TextEdit in Snow Leopard. And I'd like to show you how valuable these various enhancements are, and how simple they are to implement so you can extrapolate that to your own applications. So starting with Concurrent Document Opening, as you're probably familiar if you open a ton of documents in TextEdit, or you're loading over a very slow network, you're going to be prepared to see this guy. This mini pizza of death or the weight curse.
Obviously because the loading process is blocking the main thread, preventing it from processing any user events. Concurrent Document Opening allows us to push all of these document-reading processes to background threads, allowing us to see a lot more of this guy. Less of this guy since we are no longer blocking the main thread. And enabling Concurrent Document Opening is fairly straightforward. You simply need to make sure, Step 1, that your document creation process is thread-safe. There's several entry points in NSDocument, including your init method and your reading method.
First of all, you need to make sure that you disable and do registration within those, for the duration of those methods. That's a good idea to do anyways, but it's especially important in the context of Concurrent Document Opening. You also need to make sure that your reading methods are thread-safe. That they can be run concurrently, open multiple documents on background threads at the same time. The same goes for makeDocumentWithContentsOfURL and openDocumentWithContentsOfURL display error.
These overrides on NSDocumentController. Now chances are that your application overrides one or none of these methods, in which case you need to do nothing. But TextEdit, for example, overrides the openDocumentAsContentsOfURL to handle the transient document before displaying either documents that are loaded. Just after doing that the second and final step is to override NSDocuments canConcurrentlyReadDocumentsOfType, this class method. And ReturnYes for all the types that you can safely read concurrently. And here we see the implementation for NS, for TextEdit. And we ReturnYes for any type that is not HTML or web archived. That's because WebKit currently is unable to read multiple HTML documents concurrently.
So we ReturnNo for those types. So this is fairly straightforward and very worthwhile. Your users will really appreciate being able to do this and not having the application spod while you're trying to load. Now, you're probably wondering what is this type conformsToType and kuTTType constants? Hopefully you're familiar with them, but if you're not we'll introduce them briefly. These are, deal with UTIs.
They're Uniform Type Identifiers. UTIs extract all this various file type information that we have the system including file extensions, HFS type codes, MIME types, NSPasteboard type names, and your own custom NSDocument type names. They are organized in a unified hierarchical type system, which allows you to reduce complexity when dealing with the interrelated types in your NSDocument applications.
And in connection with this system. Snow Leopard recognizes over 400 UTIs out of the box, and the UTI database is extensible with your own custom types and your own applications. So for adopting UTIs, in TextEdit we first go to the Info.plist. Here we see the entry for the RTF type, and I've highlighted the CFBundleType extensions, MIMETypes and OSTypes entries.
Now, as I explained, all of these, all this information is extracted away by UTIs, and we can actually completely get rid of it and replace it with a single entry of LSItemContentTypes with the public .RTF UTI. Now, this is just a representative sample of TextEdit's Info.plist. There are seven or eight types that TextEdit supports.
And so you can imagine that this is a fairly, this simplifies your Info.plist significantly. In the Info.plist we also switch from the NSPasteboard type names to UTIs for the Services declarations. And in code wherever we were using the old custom type names, we switched to the System Defined UTIs.
Now, this carries with it an interesting implication, because wherever we used to compare types with isEqual since they were just strings that we defined, that's no longer strictly appropriate because that ignores all of the rich hierarchical information we have in UTIs. The proper thing to do is use this, as you saw before, NSWorkspace API Type conformsToType which will ReturnYes if a type is the same as or a sub-type of another type.
So this lets us access that information. Now, in TextEdit there are relatively few changes that we needed to make to accommodate these things. Here you see five method overrides in NSDocument and NSDocument Controller that either take types as arguments or return them. And so here we needed to make sure that we were using the proper type names and using this new API.
The same goes with the methods that implement the services, the TextEdit events. Now, compare that with all of the various API and overrides that are in TextEdit that didn't require any changes. And you can understand that this is a fairly simple change. The changes are well localized to a specific subset of your code and it's not a very complicated thing to do. So hopefully you can extrapolate that to your own applications, then participate in UTIs as well.
The next enhancement is one that I really appreciate. It's Save As PDF. Now, if you're like me I have to remind my wife and my mom fairly often how to save an arbitrary document as a PDF in various applications. If you go to the Print panel, find the Save As PDF button and do that.
It's not a very discoverable UI, especially for novice users. So we've provided in TextEdit this Save As PDF menu item right under the Save As menu item, so it's much more discoverable. And you're probably thinking, well, in that case I would have to do a lot of this work myself. That's a lot of additional code to maintain. And yes, we could have had you implement dysfunctionality like so, taking care of the NSSavePanel.
Bringing it up, setting it up, getting the response and dealing with hidden file extensions and so forth. Not something we wanted to make you do. But here we see the NSPrintSave path entry in the Dictionary that we passed to printDocumentWithSettings. If we actually can get rid of that, the printDocumentWithSettings method will bring up the SavePanel for you and prompt the user, allowing you to get rid of all this code. Making it a much simpler process it allows you to maintain, and now you really have no excuse not to implement this in your own applications. Last but not least is Text Checking.
There have been various types of text checking that have existed in Mac OS X. It started in 10.0 and even earlier. Spell checking. And Leopard's. In Leopard we gained grammar checking, automatic quote substitution, and link detection. In Snow Leopard we gained language and script identification, data detectors, automatic dash substitution and text replacement and spelling correction.
Some very powerful features, and we wanted to adopt these in TextEdit to showcase them. And we'll see just how complicated this was to do. We simply added four preferences to the TextEdit preferences pane and bound them to NSUserDevelopsController. And called for methods on NSTextView to enable or disable them as requested. And that's it.
Not very complicated in other words. And adopting that, if you use NSTextView should be just as simple and we encourage you to do so. There's a lot more to the text checking APIs in Snow Leopard. There are new APIs, both in NSTextView and in the spell checker that are much more general and lets you do this text checking on arbitrary strings. There's API that lets you modify and do custom text checking as well, and so we encourage you to find out more. Again, go to the Text Processing talk on Friday. So in summary, four enhancements. Concurrent Document Opening.
Simply make sure that your document creation is thread-safe and override one simple method on NSDocument. UTI Adoption. It really simplifies your code and your Info.plist. And involves fairly localized easy-to-understand changes. And Save As PDF UI plus one simple method implementation. And Text Checking. We added UI prefs and four method calls. All these things very simple. Very worthwhile.
Please do the same in your own applications. Now, moving on to something completely different. NSCollectionView. Now, we've worked hard. Well, we introduced NSCollectionView in Leopard, and there have been lots of improvements. We've worked really hard on it in Snow Leopard. And we've made sure to address all of the, or as many of the bug reports that we could that you have so graciously filed on it. We've ensured smoother relayout animations, more predictable layouts, and better auto-resizing behavior. The selection indexes method, propertyOnAsCollectionView is now properly KVO-compliant as was advertised in the documentation for Leopard. And it's much more reliable. You shouldn't have to worry about any unexpected crashes while using NSSelectionView in Snow Leopard.
And there's much more that I think you will appreciate. One other big thing though, is that we noticed when people were binding fairly complicated prototype views to their NSCollectionViewItem's prototypes, sometimes during the replication of these prototype views, the bindings would be inexplicably lost. And some people found various work-arounds for this, usually involving overriding NSCollectionViewItem's copy with its own method. And there they would either set the bindings manually, or load a NIB that would provide the view to the new collection view item.
Now, we thought this was a really good idea, and we decided to make some appropriate changes to do a similar thing. Here is the NSCollectionViewItem declaration in Leopard. In Snow Leopard we've made a significant change here. It's now no longer a subclass of NSObject, but NSViewController. Thereby inheriting all of NSView Controller's NIB loading behavior, making this a lot easier and a lot more reliable. Adopting this new NSCollectionViewItem approach is very simple.
You move your prototype view to a dedicated NIB. Connect the prototype view to the file's owner, which is actually the NSCollectionViewItem, with your bindings and other connections. And in, where you instantiate your NSCollectionViewItem in your NIB, you set the NIB name and bundle identifier there so it can find that NIB.
This not only allows us to do exact replication of your item views, but it also allows us to do more efficient and lazy loading of each of the item views. So it allows you to have collection views with many, many more contents because all of that is done lazily. This is also completely backwards compatible with Leopard. If you make no changes to your applications using NSCollectionView, it will still work fine just as it did in Leopard.
So, but we really encourage you to make those changes because it is so simple and very worthwhile. So we actually have a quick demo just to show you how simple this is to do. So if you have used NSCollectionView you've probably looked at this sample code. It's a really great sample icon collection that shows you how this works.
You can see. I'll demonstrate for you just how well NSCollectionView is working in Snow Leopard. Things are very smooth looking, and this is even without Layer Back Mode on, so that's just a demo for that. So now we'll do the work very quickly in just a couple minutes to use the new NIB loading behavior for our prototype views. So here we see the NIB that contains our NSCollectionView and the prototype view. We're actually going to cut this view out of this NIB completely and create a new view NIB.
Get rid of the one it gives us there and paste in the one from the other NIB there. Now, the next step is to create, to make the file's owner the NSCollectionViewItem and connect that to the view so it knows what view to load. Now, we need to rebind all of the bindings from this view to the NSCollectionViewItem. So the first is we set the transparent property, bind that to the filesOwnersRepresented.
Oh, actually the selected property. And will NS negate Boolean. This will allow us to simulate the selection highlight since this is a box drawing a background here. And here is our prototype view. We want to bind this image view to the filesOwnersRepresentedObject.iconproperty. And we'll rebind this to the filesOwners, this text view, RepresentedObject.name.
Go ahead and save this. It's ViewPrototype, is what we'll call it, and we'll add it to our project. And we come back here to our CollectionViewItem we've instantiated here. And here it sets to. We've set it to load the ViewPrototype NIB, and that's all the changes we need there.
Make sure those are saved. Come back and run. And you see its working just as it did before. It's not a flashy demo, but it shows you just how simple it is to do, and we have a CollectionView that's working exactly as it did before. So we really encourage you to make that transition in your NSCollectionViews. Now, there's one last feature that we added to NSCollectionView that I'd like to demonstrate for you, so let's TextEdit here and select a few things And Drag and Drop. We have. Now, Drag and Drop support in NSCollectionView, one of the most requested features in NSCollectionView, so.
Yes.
[ Clapping]
That really, Drag and Drop really brings us up to par with the other Collection-type views, NSTableView and NSBrowser and so forth. And you'll find that the APIs are very familiar if you've used NSTableView's Drag and Drop APIs. The APIs use indexes for efficiency's sake, so we're not shoveling around larger arrays of represented objects or NSCollectionView items.
And we have new APIs to facilitate this. ItemAtIndex, which, which will return the NSCollectionView item for a given index in the collection. And frameForItemAtIndex will return the frame that a view will be displayed in on the CollectionView. This will return the result without even loading the view from the NIB, so this allows us to continuously be loading our views.
Of course, the Drag and Drop API allows for local reordering as you'd expect. And is compatible with all NSDrag Pasteboard clients. Anything using the NSDrag Pasteboard will work as you'd expect with NSCollectionView. The gesture to perform a Drag and Drop is a click-and-hold. We have to do this to differentiate Drag Selection from Drag and Drop. But we encourage you to start using CollectionView.
There's lots of new features there. Moving on to some of NSCollectionView's distant cousins, NSTableView and NSBrowser, there's going to be a talk devoted to these two classes, Presenting User Data with TableViews and Browsers on Thursday. We encourage you to see that if you want more detail about the enhancements.
The many enhancements in these classes. But here's a few highlights. NSTableView now has API to reload specific rows and columns if you know that the data backing those rows and columns have changed. So you don't have to load the entire view, which can be inefficient. We've allowed much more customization of the selection highlight behavior and drag destination highlight behavior. And you can control which cells or columns can receive focus as you tab through a TableView.
You can configure a column. Each individual tableColumnSizetoFitBehavior when you double-click on the column header. You can configure how that will resize. And you can control which columns and how it can be ordered by the user and how those columns can be reordered NSBrowser has some significant new APIs.
If you're familiar with NSBrowser the old way to do it was the delegate was told to push a whole bunch of items themselves into an NSMatrix, and you'd have to do that for each column of the browser. This wasn't very intuitive and made it somewhat cumbersome for people to use NSBrowser. But we provided a new item-based API, which will pull information from the delegate about a tree of items.
It's much more intuitive and will make NSBrowser a lot easier to use than Snow Leopard. There are several other APIs and enhancements, most of which require using the new item-based delegate, so we really encourage you to switch as soon as possible. Some of these include variable row heights, allowing the user to edit the contents of a browser. And custom preview columns and column headers. Now, what are those, you ask.
Here's a screen shot of Finder. As you know, as you heard from the keynote, Finder is now using Cocoa and indeed it does use NSBrowser. And here's a screen shot of, we've connected to a server and selected a file. This part that shows the information about a server is a column header, and this part that shows information about the selected file is a preview column. Using these new APIs you can replicate all of this behavior exactly. So that's all for those topics.
[ Clapping ]
So now I'd like to talk a bit about File System Efficiency. File System Efficiency is a large effort we undertook in Snow Leopard to reduce the number of times we hit the disc. As you know, disc drives and especially network drives, network servers, etc., can be unpredictable as far as performance.
And they often are an important piece of the application performance puzzle. So to that end, we focused on developing NSURL as a central API to reference files, and also to get information about them. So NSURL now provides much more complete access to things you want to know about files. So file properties basically.
And one thing this does is this eliminates the need to convert between various representations. You no longer have to convert to an FSRef to get this information or convert back to a POSIX path to get that information and so on. In addition, we now cache property values in NSURL.
So that if two different parts of the program ask the same NSURL for the same property in a very short time where it hasn't changed, NSURL can respond very quickly. We also took this opportunity to do some API enhancements and improve and add more NS errors and provide better error reporting throughout. So the property access in NSURL is fairly straightforward. getProperty. Oh, I'm sorry.
getResourceValue and setResourceValue. These two APIs get or set the value of one property. You can also use the bulk versions resourceValuesforKeys, or setResourceValues. Now the properties you can use here, there's a lot. And I'm just going to give you a small sampling here. You can get or set the name, for instance.
You can ask for the localized name. You can ask whether it's a package, etc. Now note that some of these properties the values are actually NSImages or NSColors, and these are AppKit objects while this is foundation API. So these APIs will return these answers if AppKit is loaded into your application, which of course it almost always is for Cocoa applications. We also added NSURL Path Utilities. You might be familiar with NSString Path Utilities where you can manipulate paths, you know. Add file extensions, remove components and so on. We now have the equivalent for NSURL.
[Applause] Thank you. And we also have this one other notion, this new concept of File Reference URL. Many of you may be familiar with FSRefs which basically are file references that can actually track a file by reference, by ID so that the reference is valid even if the file is renamed or its parent Any of its parent directories have been renamed. This is useful in some specialized cases. So NSURL now also features this. Basically you create one with the method called File Reference URL.
Here's an example. I'm creating one URL, a filePath URL. And then I'm creating another, a second URL which is a fileReference version of that URL. Here's what the two URLs would look like. Now, they reference the same file. However, the first one has a path in it while the second one has this ID in it.
But note that the second one is still an RFC compliant file: URL, so it's still a very valid URL. Now, this is transparent for most uses. Meaning you can still access resource values. You can extract the path and so on. However, it is really for specialized uses. For instance, in the context of a regular application you probably only want to use this for the files that the user might manipulate and move around, and that often involves documents, for instance. And since NSDocument already uses this facility you might not actually need to yourself.
Another thing to note here is that although this looks like it might be a good solution, this is actually not a good-- this is not meant for persistent, because the ID you get there might be different between different reboots of the machine. So this might not continue referencing the same file correctly after a reboot.
For persistence you actually want to use bookmarks. We have this new concept of URL Bookmarks, which is basically an NSData that contains a persistent form of NSURL. You create one with this API here, bookmarkDataWithOptions, and it returns NSData for you. Now the options here include the ability to ask for a fairly minimal piece of bookmark data for instance.
Or you can even choose to ask for bookmark data, which is the same as an alias data file from 10.5. So you can actually save these away and read them back as alias files on previous releases. To recreate an NSURL back from a bookmark you would use this API, URLByReservingBookmarkData.
There are two options here I believe. The first option says whether this API should mount volumes, if volumes need to be mounted. And the second API says where this API should put up UI if authentication or any other UI is needed. And of course if you don't provide those options and those are needed, then this API will fail and return an error into NSErrorArgument. NSFileManager has a lot of changes again, to support this new NSURL direction. NSURL versions of existing functionality in here are just three samples. Copy, move and removeItem now have URL versions. We also can now do Directory Enumeration with URLs.
This new API returns a Directory enumerator like before. Now, note that there are some extra arguments here for enumeration. One of the arguments is keys. You can provide as a hint the list of properties you're going to fetch. This is just a hint, but if you provide this list this API might pre-fetch these properties for you making it faster to enumerate through the items.
You would provide nil if you just want the default behavior. You can always of course ask for other properties as well. It's just this might speed things up a bit. The options argument allows you to skip subdirectories or skip package contents, which is actually quite nice. And skip hidden files if you want.
And finally note that this API takes an error handler. It will be invoked on every error. If you ReturnNo from this on any error then the enumeration stops. NSFileManager also has a Safe Saving API. This is equivalent to the FSExchangeObject API that we have in Carbon. Most of the time you do not need to use this.
You can get away with just saving files atomically and that's good enough. But this is what you really need to do document level saving totally correctly. And since NSDocument uses this, you may never need to. But of course, if you're writing your own document-based application not using NSDocument, this is a good API to look at. Now, FileWrapper may get the award for one of the most improved classes in Snow Leopard.
And of course, many of you might be thinking FileWrapper, what's that? What does it do for me? It's an often-ignored class. What FileWrapper does it's a representation of File Packages. It can represent flat files, symbolic links. But more commonly it represents a folder full of other files, which represents a document.
What we call a File Package. In Snow Leopard there's a lot of API cleanup. We now use NSURLs, return NSErrors. And we've also given control over lazy and mapping behaviors, and implementation was just pretty much overhauled throughout. FileWrapper also has more complete support for metadata. It will now preserve extended attributes, for instance, of the files you put into it. [Applause] Thank you. Some FileWrapper fans out there. Now, here's the Reading APIs. initWithURL, readFromURL.
Now, NSFileWrapper typically tries to do the right thing. What this means is if you have a pretty large folder with a lot of files in it, FileWrapper will not read the whole thing into memory, for instance, because, you know, it doesn't need to. That's a default behavior. However, note this scenario where the user drags a, say, a folder into your application and the next thing they do is they'll go and delete that folder. So to accommodate those kinds of scenarios we do have various options.
The immediate option means do copy everything into memory, and this is something you might want to use when the first time an attachment or a document is brought into your application. Of course, after that when you create FileWrappers for places you know you might not need this. The other option is the do it without mapping option. FileWrapper might often use File System Mapping as a way to optimize its behavior. And it will avoid File System Mapping when it knows the files are coming from a network directory.
But there are times when you might know better, so you can provide this option to say don'tMapAtAll. For writing there's this writeToURL API. This also has some options, but I actually want to talk about the third argument here, the original argument. This method now does a very good job of incremental saving.
What this means is if you already have your FileWrapper saved on disc somewhere and you're saving it elsewhere with a little, did some modifications. If you provide the location of the original one, FileWrapper will actually use hard linking as a way to very efficiently copy the items that have not changed in between.
So it enables incremental saving and does a very good job of it. And I mean, notice like even something like a keynote document, this presentation we have here. Or let's actually talk about presentations you saw yesterday which have multi-megabyte movies in them. Most of the time when the user hits Save, all they're changing is the text in the slides. They're not changing the movies, the sounds, the pictures. So FileWrapper can just hard link those, so it's a good win. NSWorkspace we talked about before. Here's a few other changes. The NSURL changes, I just want to highlight these.
It now has asynchronous file copy and recycle methods. Now, these are truly asynchronous, meaning you call these, the file copy or recycle starts to happen and these methods return while still going on. So this is analogous. Earlier we used a carwash analogy. This is analogous to you going to the carwash, giving them your keys, going back home and then they call you later you tell you your car is ready, so that's what this one does. And the callback here is the completion handler block that both of these take. And I want to give you an example of how these work. Let's say you want to duplicate three files. One of these files has already been copied before.
Another one of these has not been copied before. And the third one actually does not exist. So when you call the duplicateURL's API the results you get back are you're going to get back this Dictionary, newURLs. It's going to tell you that the item that was not yet copied has been copied as NotYetCopied copy.
But note that the one that was already copied is going to be copied as AlreadyCopied copy 2, because that's what the Finder would have done of course. So it actually tells you what the name of the copy is. And finally, note that you'll get back an error, which tells you that the file Nonexistent could not be duplicated because it was not found.
And again, these error messages will adjust themselves if there are multiple files that cannot be copied and so on. Now, at this point I just want to pause and talk about NSErrors. You're seeing a lot of NSError arguments in these APIs we're adding. But note that we're adding NSError API, NSError arguments to APIs where having NSError matters. We don't add NSError arguments to every single API. In fact, we add it to a small subset of new APIs. But we add it in cases where it matters, because where the error is going to be bubbled up to the user.
And we want you and your applications to be able to present these errors without having to parse them apart, tell what the kind of error it is, you know. Have a big switch statement and so on. You just want to take this as-is and present it to the user and have the appropriate warnings, recovery options and so on displayed. And so that's what we really encourage you to do as well. You know, if you add NSErrors in your program, choose the places where they will really matter and do a great job of making sure the user never gets some, you know, horrible error message.
That they're always clear and concise, and tell the user how to recover from it. OK. So at this point I just want to touch upon a few remaining topics. Shorter topics. So one is NSSavePanel. There's a bunch of changes in NSSavePanel. One of the tuning methods we've added are to do sheets using blocks, which is actually a very natural step. So here are the two APIs. And I want to show you how these APIs, how these work compared to Leopard.
So here is how you brought up a save sheet in Leopard. You would basically create a savePanel, and then you would go out and call beginSheetForDirectory and provide it six arguments. Two of the arguments were an object to invoke, and a Selector to invoke on that object when the user dismissed the SavePanel. And then you would implement that method, of course. Here is the saveDone:returnCode:context: method. The context allow you to pass some context in, because sometimes you need to do that. And in that method you can look at the result and do whatever you need to do.
In Snow Leopard this has been reduced to just this. It's pretty much equivalent. You now call this method beginSheetModalForWindow and it takes two arguments. And the second argument it the blockToExecute when the Save Panel is dismissed. Note that the work you do here in Leopard is the same as the work you do here, so it's exactly the same code as far as the amount of the work that's been done.
Now, also note that in the Leopard case here there are three arguments. The panel, the return code, and the context. While in the block version there's only one argument, and that's the result. That's because anything else that needs to be passed into this block can actually be captured as a part of the block.
For instance, note here that the panel, which we created here, is actually captured by the block, so we don't need to pass it as an argument. And the same of course goes for the context. Blocks are a great way to eliminate all these context arguments that we need to add in a few places. Now, while speaking of NSSavePanel, there's actually a few nifty openSavePanel user level features that I'd like to highlight for you.
[ Silence ]
So one of them is that you can now right-click on the column header in ListView and add additional columns. So here is your OpenPanel for instance. Just right-click. There's a bunch of columns to select from and bingo. You now have your kind and your size columns in your OpenPanel.
You can now hit cmd-shift-period to temporarily view hidden files. There you go. Oops. Let me show that again. Sorry. OK. Slow motion. Bam. There you go. OK. And note that the user can do this in the context of any application. There's also API that lets you control this better. So if you decide your application needs to edit that command, these .files or hidden files on a regular basis, you can actually control this by providing UI for the user if you wish.
Here's another option. Kevin touched upon this earlier. But you can now double-click. In the case of OpenPanel you hit right edge of the header to automatically resize a column. So here is the Kind column, which is a bit truncated. You go ahead and double-click right there and it will autosize to show the contents, and that of course works on any column. And last but not least you can now hit Space in the OpenPanel to Quick Look selected files.
So here we have a selected item. Hit Space, and you will be able to Quick Look the files. And if you have.,.if you have multiple items you can go back and forth and still this way more carefully select exactly what file it is that you want to open. Now, NSImage also probably gets an award for most improved overhauled class in Snow Leopard.
And NSImage, by the way, is also another example of the benefits of Cocoa Extraction where we have done a ton of implementation changes under the hood and, but in a binder compatible way for most clients and the way which gets you a lot of performance benefits. So performance benefits is a big part here. One way to achieve this with better impedence, match with the Quartz-type CGImage.
And we also no longer cache images in windows. We actually cache them in other ways, which are much more compatible with Quartz and much faster. We also took this opportunity to introduce some APIs and deprecate some APIs as well. Now, I'm just going to enumerate these APIs very quickly but, and give a pointer to a session where this is covered. You can now create NSIMage directly from CGImage and you can also very efficiently extra a CGImage. You now have. [Applause] Thank you. You now have better control over drawing parameters of NSImages.
You can now hit-test a point or a rectangle in an image. And what I mean by that is you can check a point or a rectangle to see if it's transparent. This is, for instance, one thing, which previously required you to extract pixels. Rummage through the pixels, figure out the bitmap format just to see whether it was transparent. You can now do this with one API. You can now automatically interpret, this is actually automatically done for you, orientation info of pictures coming from cameras so they will appear correctly.
And you can set accessibility in the description, which means when the image is displayed in various contexts, VoiceOver will be able to read the description to users. And you can pass NSImage directly into Core Animation setContentsMethodNow, while before you had to extra a CGImage. And we now have many new standard images. As you know in 10.5 we started this.
We started creating brand new high-resolution standard images, and we've added many new images to that set. So collect them all. OK. And the talk to go to to hear more about NSImage and a lot of other fascinating facts about NSImage is, this is Session 111 I think. It's Thursday at 3:30.
NSImage in Snow Leopard. Along those lines I just want to talk quickly about NSView Layer Redrawing. If you use NSViews with layer backing, one thing you might have noticed that is when NSViews are using AppKit generated layers, when that view is being animated, larger or smaller, the layer is redrawn at every step.
And that's to give you the highest fidelity presentation. But now in Snow Leopard we have this API, setLayerContentsRedrawPolicy, which lets you stop that from happening and control it better. In Leopard, the behavior was basically this. NSViewLayerViewContentsRedrawDuringLiveResize, which redraws every step. You can now choose one of these other options, including neverRedrawIt or drawItOnlyONceBeforeTheResizeStarts and so on.
Now, in addition to this API we have this other API that lets you control how the layer should be displayed if it's not redrawn. You can for instance have the layer scaled in various ways. Or you can have the layer pinned to an edge or corner. So if you're using NSViews with layer backing, and you're having them resized, this is definitely an API to consider. Multi-Touch. You might have heard about Multi-Touch at the last WWDC.
We now have support for standard gestures on the trackpad. So Magnify, Swipe and Rotate. And although we exposed this in Snow Leopard, this actually works back to 10.5.2. However, now we've also gone ahead and added support for arbitrary touch events and these work on Snow Leopard only. This is an opt-in at the NSView level. So your view would call setAcceptsTouchEvents and will start getting touch events.
Now, until any view in an application calls this, no touch events will be delivered to the application, or no individual touch events. And our newest responder methods, which is of course what we always do with events, touchHasBegun, touchHasMoved, touchHasEnded and so on. These are fairly straightforward. We've also added a new class called NSTouch.
This is analogous to the UI touch class from the iPhone, but also different in some important ways. Now, to hear more about Multi-Touch and any of these events topics, go to User Events in Cocoa, which is tomorrow afternoon at 3:30. Another API we've added is DockTilePlugin. This is actually a new protocol.
Now, you've seen iCal and how spiffy it is being able to show you the date, even when it's not running. And you might have wondered how you do the same thing without hackery, and you can now do it with this protocol. And I was going to show you, I was thinking I shouldn't show you the whole API codes, you know.
We're not showing whole APIs. But in this case it turned out it's so embarrassingly simple I'll just show you the whole API. There's two methods and you only have to implement one of them. So basically what happens is you create a plug-in inside your application. You put the name of your plug-in inside your Info.plist as NSDockTilePlugin equals whatever the plug-in you created is.
And you go and implement this protocol. And by that, I mean you implement setDockTile. The dock will call you with the DockTile at the appropriate time, and you can go ahead and fill it in and do whatever drawing you need to do. And you can update it whenever you wish.
And, you know, you can update your DockTile even when your application's not running. It's very, very simple. So I think at this stage we are running short on time, so it's time for Sudden Termination. Now, what Sudden Termination does is it enables your applications to be quit very quickly. And by quit I mean killed very quickly.
They don't even get a chance to quit. It turns out that whenever you tell an application hey, it's time to quit. Quit. Even if the application has got nothing to do, it still fiddles around a bit. Takes its sweet time. Sometimes it even goes into page your stuff in before it decides it can quit, and that's just not good.
You know, you want the applications to go away as soon as possible if they can. So for this we have this notion of if you're clean, which means if you can be killed without any loss of data, we'll just kill you. Now, there's API where of course an application can say hey, I'm not clean. I'm dirty.
And the way it does that is it calls disableSuddenTermination and enableSuddenTermination. You can either call this around a small block of code, which, where you have some critical activity going on. Or more likely you might call it for instance, when the user dirties a document, types something into a document, you would call Disable. And later when the document is saved you would call Enable. So basically during that time, since the document is edited but not saved, the app would be unkillable. Now, note that AppKit marks an app as dirty during event dispatching.
So this actually takes care of a lot of little cases so that you don't have to worry about all these individual little cases. Whenever the AppKit sends out an event during the processing, the app is considered dirty. This requires opt-in of course. We can't just go start killing apps left and right. It's very easy to opt-in, though. You either call enableSuddenTermination when you're launched, or else you go put a key in your Info.plist saying that yes, you can start life off clean.
So Sudden Termination we have added some tool support for it. Activity Monitor. The Activity Monitor application has some support. If you right-click on the column headers in Activity Monitor, you can choose a bunch of other, I don't know if you knew this, but you can add additional columns to be displayed. And one of them is the Sudden Termination column, which is right here. Now, note that here it says Yes for apps that are actually killable, and No for apps that are not killable at this instant.
So of course, if they are not killable, what that means is they'll just go through the regular Quit Negotiation and regular Quit Path, so it's not like, you know, just because they're not killable it doesn't mean it's the end of the world. It'll just take a little longer to quit. But the more apps that are killable, the faster log-out or shut-down will be. Another place where we added support is Instruments where you can find out why an application is not killable.
So let's focus in on this middle section here. Note that the count, the disable count is alternating between 0 and 1, 0 and 1. Well, that basically indicates the AppKit event is enabling and disabling it for you. But note that suddenly the count goes up to 2 and 3 and starts alternating between 2 and 3, which means the app is no longer killable because the count is not 0.
That's where the 3 is. So by clicking around in these events where things look fishy, you can note from the back trace on the side here, you can note that NSDocumentsUpdateChangeCount was called. And in fact, this corresponded to a time in TextEdit where I typed a character into the new window. And since the document is not dirty and not saved, TextEdit is now unkillable, and that just basically reflects that.
So this is a great little tool to find out why your application may not be killable and you're trying to make it killable, so definitely look into it. Now, we are relatively short on time so, and we have a ton of other important changes, so I'm just going to show them to you all now. And actually this is just a part of them.
And I'm really going to not give you much time to read through this stuff but, so I'll just leave it up a few seconds. Read quickly. Come on. You too. And but one thing I'm going to do is point out where to go for much more details on all this stuff. And of course, one answer that we always like to say is release notes. Release notes might not be the best-written prose in the world. It's basically from engineers, you know, typing on the keyword right to your eyes.
But it does communicate a lot of the changes that we have done, so it's a good thing to browse through. We them for AppKit and Foundation. We also publish these things called Changes docs. If you look through your Snow Leopard documentation you might have noticed AppKit Changes, Foundation Changes and so on. In fact, for a lot of other frameworks as well. And those actually enumerate every single change that is in the appropriate APIs. You can also just open up a header file.
Like let's say you're interested in NSCollectionView or NSTableView. Go and open the header file, search for 10_6. That's a great way to see what got added, what got removed, what's marked for deprecation. And of course, finally to get the official story on a lot of these changes refer to the documentation. The Doc folks have been working feverishly to keep up with these changes, and a lot of good things have been documented so you can find out the real truth. What the engineers meant to say but couldn't in the release notes.
You can find it out there. Now, typically at this point in the talk is when there is one more thing. Well, I have a few more things slide. Woohoo. And this is basically a teaser for release notes so I can go get you to take a look at the release notes. So I'll just tell you a few things you can do in 10.6, but not necessarily tell you how to do them. You can, for instance, now put URLs directly into Preferences. And this will do the right thing with regards to your abbreviating your home directory.
It will also write it in a way where you can read it back on 10.5 without support of this API. This is something that we got a lot of questions about. You can now source file names or in fact any strings like the Finder does. So it would be exactly like compatible with Finder as far as sorting your strings, which of course is important in different localizations. You can now change the Desktop image fairly easily without having to resort to hackery.
You can get a compiler warning for this. NSLog(Message). And here the message argument here is a variable. Now, if you're wondering why should I get a compiler warning for this, it's a good thing that you'll get a compiler warning for this. But basically it involves potential security considerations where you might provide a format string that could cause a malicious activity. So the compiler will now warn you for this and other related usages, which are fishy.
You can now have NSErrors display a Help button in alerts. As you know, NSErrors have the ability to return recovery options where additional buttons will appear in alert panels, letting the user do recovery steps. You can now have a purple button up here on the alert panel, which will bring up Help documentation if you wish. So this is all part of NSError. And again, this is all along the lines of making NSErrors even more useful. You can now animate integer and color-valued properties in NSView. Color-valued properties were actually animatable before. We document them as such.
But it turned out they were only animatable in some cases. You can read the release notes and find out when, but now both of these actually work. And of course integer valued property also includes BOOL valued property. And last but not least, in your Garbage Collected application KVO observers will now be automatically removed when finalized. What this means is if you have finalize methods where all you're doing is removing KVO observers, you can now get rid of those finalize methods which is of course very good for Garbage Collection.