Frameworks • iOS • 56:40
Understanding the Foundation framework is essential for building good software on the Mac, iPhone, and iPad. As Foundation evolves, it is important to keep your knowledge up to date. Get an overview of the new features and important changes in the Foundation framework in iOS 4. Learn about the new blocks feature and how it's used in the new Foundation APIs as well. This session will also help orient you to other sessions that will cover these technologies in more detail.
Speaker: Chris Kane
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 Chris Kane and I'm an engineer with the Cocoa Frameworks team. Today, I'm going to be talking about what has changed in Foundation for iPhone, not iPhone OS 4, iOS 4. iOS 4's Foundation represents the first major update to Foundation that you folks working with the iOS SDK will have seen.
In iPhone OS 2 and iPhone OS 3, we saw a Foundation in the system which was essentially the system, the Foundation that was in the Mac OS X, 10.5 with, you know, a few changes here and there; some APIs were missing and there were a few of the little additions. In iOS 4, now we have a Foundation which more or less corresponds to the Foundation in Mac OS X, 10.6 with, you know, some things that are, you know, different still, including some new APIs that haven't yet appeared in Mac OS X itself.
Now there have been a lot of changes. I can't cover all of them so I'm going to be covering the highlights here. I'm going to begin by talking about blocks and new block-based APIs that we've added to Foundation and then I'm going to cover some additional changes that we've done.
So I'm beginning with blocks. Why? Well, blocks are a very interesting, new functionality that we've added and they're a very important new functionality as well but another key reason that I'm beginning with blocks is that as we, we'll see a little bit today but also going into the future, block-based APIs are going to be very important. And as we move forward, it's very likely that a block-based API may be the only way to get access to certain functionality. So it's very important that you understand blocks and understand how to use them properly in order to access all the available functionality in the system.
Well, for those of you who may not have seen all of the public materials that we've had, out since at least Snow Leopard was released back in August last year, I'm going to do a little review of blocks. So what are blocks? Well, a block is an object which represents a chunk of code. A block is used much like a function.
If you're familiar with say functional programming languages, you may have seen closures. In C++, you may have run across things that, constructs that are called function objects. You know, certain ways you write C++ classes and those things are very similar to blocks, not quite the same though but very similar in spirit to blocks. Well, blocks are objects with some code, that know how to execute some code.
The key interesting thing Ob-C is that they are like NSObjects. They respond to all the NSObject methods. But blocks are not simply an Objective-C bit of functionality. Blocks are available to all the C-based languages for which Apple ships a compiler, that's C, C++, as well as Objective-C and Objective-C++.
Now, as I say blocks are bits of code. Blocks are used a lot like function pointers. Here, I'm going to demonstrate the basic syntax of using a block or declaring a block, I should say. First, I have a variable there on the left called myBlock and in front of it is a carat. The carat is the signal to the compiler that you're intending to declare a block.
Block-type declarations look a lot like function pointer declarations with the star or the asterisk replaced with a carat. In this case, the block returns an int, so that's the return value, the return type I should say, there on the left and it takes one argument, which is also int. So a very simple block.
On the right side of the assignment operator, we have a block literal and you'll see, you'll be seeing these a lot and you'll be writing these a lot in your code. At the left side of the block literal, we have the carat sign followed by the parenthesized argument list just like a function argument list. In this case, we have of course the one argument which is called num and then inside the curly braces, just like a function has, you know, curly braces surrounding its body, we have all the statements of the block. myBlock in this case is very simple.
It's just got one return statement in it and all the return statement does is multiply num by, which is the argument, by this variable called multiplier. Now, this particular case, the block is very simple but you can have many lines of code within the curly braces but for the purposes of my talk, I have to keep the blocks nice and short to fit on the slides. So I'm not going to be showing a lot of multiline blocks in this talk.
Well, I didn't explain what this was. I said it was a variable called multiplier which, you know, you can obviously see for yourself. Well, all this is, is a local variable. One of the most interesting things about blocks is that they can access and capture variables' values that are in scope. So in this case, I have a local variable called multiplier which the block can sort of access out. It doesn't have to be declared within the block.
In this case, it's being declared outside the block but the block can still get at it because it's in scope. Now, if I want to use myBlock which I've declared, I call it like a function. So in this case you see myBlock with the parenthesized list of arguments. In this case, I'm going to pass in 3 for the integer argument.
Now, if I change multiplier after declaring the block, nothing's going to happen. That has no effect on the block. That's the reason I talk about this as being capture, capturing the values that are in scope. So at the point where the block has been declared up there on the line above, the value in multiplier was 7 and that value is captured. Now in this particular case, I just have a constant value there but it doesn't have to be constant.
I could have gotten multiplier by, initialized by, you know, calling a function or something like that. But at the point where the block has been declared, the value is captured. So I can change multiplier after that and it will not affect the block. In this particular example, I'll always get 21. That is 3 X the multiplier 7 as a result of my printf statement, even though I've changed multiplier afterwards.
Blocks can be used, of course, then as arguments to Objective-C methods and now we're going to begin seeing where we've added new APIs within Foundation. In this case, I have a new method, enumerateObjectsUsingBlock. This method will call the block, invoke the block once for every object in the collection.
So here we see the first bug in the slides if you're paying close attention. The method is called enumerateObjectsUsingBlock and then there's a block argument following it with a type. Well, that blue box in the second line which is enclosing NSUInteger index should be extended really over all of the parenthesized material. That is the whole type of the block, that big long mess in parentheses there and then on the far right we just have the name of the argument block.
Well, within the block type, we have the return value, void. We have the carat then and then we have the parenthesized argument list, just as if you would pass in a function pointer to the method as an argument, the first argument being an object, the second argument being an NSUInteger and the third argument being a pointer to a BOOL.
So let me give an example of how I would use this new method. As I say, this method will be invoked once, oh, I'm sorry, the block will be invoked once for every object in the collection. In this case we have an array. So first, I begin, I have a nameToSearchFor, some sort of NSString and for every object in the collection, I want to ask the object for its name.
I'm going to assume that the, or I know that the objects will respond to name and I'm going to compare that with the name I'm searching for. So I may be searching for the name Bob, for example and I'm going to look at all the objects and find the objects whose name is Bob. In this case I'm going to do something trivial, I'm just going to NSLog out the index so that's the second argument that I'm getting in this block. I'm just going to NSLog the index of that object within the array.
Well, that's very boring. Instead, what I really want to do is I want to search for an object whose name's Bob, say, and then I want to remember it and do something with it after the method returns. So what I've done is I've added a new local variable called found, and in this case I've initialized it to nil.
And within myBlock now, I'm going to set found to be the object that I find and I'm going to set stop to yes, and I'll explain what that means in a minute. But if I do that, I'm going to get a compile error because as I said before, the local variables which are outside of the block which are being captured by the block are sort of, in the sense having their values copied into the block. So I can't write to that because essentially what the compiler's done is it's captured the value of nil and put that in the block.
So this is like writing nil equals object and that's going to give me a compile error. To tell the compiler that I want to, really do want to write out as it were to the enclosing scope, I need to add a new keyword, __block. This is a new type qualifier that tells the compiler that found should be compiled in such a way that I can read it in the block but also write out to it as well.
Now that stop parameter that I'm using at the bottom of the block, let me explain that briefly. What that allows me to do is stop the enumeration. So I'm writing through that pointer that myBlock has been given and I'm writing yes in order to stop the enumeration. If I have say a million element array and I, you know, find after element 3 that I don't need to continue the enumeration, well, it's very nice to be able to stop it rather than having to proceed through all million elements of the array. So that's all that BOOL and stop parameter is for. After this method returns, if found is no longer nil, I know that the block set it to something and I can go operate on it then.
Well, there are many new collection APIs that are using blocks. These are various methods on the collection classes, arrays, dictionaries, sets and index sets. We've seen one example so far, which is one example of the enumeration class of new methods. Enumerations are, enumeration methods are there to invoke a block once for each object in a collection.
Before I go on, let me do an aside here which will help, you know, make you understand or allow you to understand, you know, some of our naming conventions with these new block methods. Well, in the case of an array, you have objects in the array so the method is called enumerateObjectsUsingBlock and in the case of Dictionary, dictionaries have keys and objects and so the methods are obviously called Keys, enumerateKeysAndObjectsUsingBlock.
The type signature of the block argument which is taken by these methods is also different based on the particular collection. Arrays are ordered collections and so they have objects but they also have indexes. The index of each object is interesting and so we pass both pieces of information into the block so you don't have to, you know, somehow compute the index yourself if you need it.
In the case of dictionary, well, dictionaries have keys and objects so we pass in both of those into the block so you get them both at once and don't have to go, say looking up the object as you do say if you're using the foreign syntax to enumerate over a dictionary.
Well, in NSArray for example, and this is true in the other collections as well, and NSArray is just being an example here, we also have extended methods. So for example, there's a method that takes some options. There are different ways you can enumerate an array so we provide a method that takes options.
For an array or an index set which are ordered collections, you can also choose to enumerate only over a subset of that collection and you do that by specifying an NS index set for those collections which are ordered. Well, what are those enumeration options I mentioned? Well, for an array or an NS index set, of course sometimes it's interesting to be able to enumerate the collection in reverse so there's an option for that.
But the more interesting option is NSEnumerationConcurrent. This allows you to enumerate a collection but concurrently, that is your block may be invoked on multiple threads simultaneously as the enumeration algorithm enumerates, that is calls the block once for every object in the collection but it may call it once on multiple threads simultaneously.
And this can result in a nice little performance boost because you can, you know, do things simultaneously for every object in the block. Now your block when you use this option needs to be thread-safe. You need to take care of the thread safety of what the block is doing and what the block is accessing inside the block.
Well, in addition to enumeration, we have other classes of new methods which are used in blocks. One class is searching. I've already illustrated searching but using the enumeration API. Previously, we were searching for a name whose object or whose name matched a certain value. Well, we packaged that kind of thing up into other sets of methods, one example is this NSArray method, indexesOfObjectsPassingTest. The interesting thing about this method is that instead of void, the block returns a BOOL.
So the block is going to be given the same arguments, that is it's going to be given the object in the index and the Boolean point or stop value but what the block is supposed to do in this case is it's supposed to test each object and return yes if the object matches some sort of test that you want to apply to every object or return no if the object doesn't match. The NSArray algorithm in this case behind this method is going to collect all of those objects' indexes for which the block returns yes.
It's going to collect them all and when the enumeration is done, it's going to return an NS index set and so then you have the indexes of all the objects which match your particular predicate. The enumeration objects' options apply to these methods as well. So for example you can do this searching concurrently if you want. Blocks can also be used in typedefs so you can create a new type which is a block type using typedef. In this case, we have a new API which I'm going to illustrate called NSComparator.
This is a new type in our API which takes two parameters, two objects and it's supposed to compare them and return an NSComparisonResult. An NSComparisonResult, that's an existing type that is an enumeration which is either less than, equal to or greater than. So basically a comparator block is given two objects and it's supposed to return whether the objects are less than, equal to or greater than one another.
Well, where do we use this? Clearly, an interesting place is in sorting. So an NSArray has several sorting methods and we've added some more using blocks as the comparison function essentially. One example here is the sortedArrayUsingComparator method. This returns a new array which is the sorted version of the receiving array.
I have an example here at the bottom of the slide showing how I'm going to call that. Suppose I have an array called myArray FullOfStrings. Well, I'm going to call sortedArrayUsingComparator and pass in a comparator block. So the block begins with the proper declaration for an NSComparator, that is the two parameters have to be id of the block and within the block, in this case, all I'm going to do is I'm going to pass the two strings essentially to the localizedStandardCompare method and return whatever its result is.
So in this case, my block is fairly simple but you can see here the power of the new block syntax. Instead of having a comparator function or comparator selector which is implemented off somewhere else within the API, you can put the comparison logic right there with the sorted array, you know, method that you're calling. So the logic doesn't have to be separated, the logic that's being used for the comparison doesn't have to be separated from the actual creation of the sorted array itself.
Well, just as with enumeration, there are some sorting options. The first option, you can sort concurrently if you want and this again, just like with enumeration can provide you with a speed boost. If you pass in this option, again, your comparison block needs to be thread-safe and what this does then internally is it invokes a completely different algorithm for sorting which sorts concurrently.
It uses, you know, up to all the cores on your machine in order to do the sort. There is also a new option we've added which has long been requested, one for stable sorts, if you want to do a stable sort. We've also provided a new option for that.
Another new API we've added, in this case to NSArray is binary search. Here we have indexOfObject inSortedRange options usingComparator and you pass in again a comparator block to do the comparison in order to implement the actual binary search. So this is an example of a new API for which there isn't a non-block alternative.
Strings can also be enumerated. We've added a new API to enumerate pieces or chunks out of a string. The new enumerateSubstringsInRange options usingBlock method takes a block which gets several arguments passed to it as you can see there and you can choose to enumerate the lines in a string or the paragraphs but also the words or the sentences.
Now clearly for words and sentences, some form of linguistic analysis is going on because of course the string might have different kinds of languages embedded within it, texts of different languages. And so some linguistic analysis is going on and that's another new piece of functionality that's been added to iPhone iOS 4. So that's blocks.
Now I'm going to go on to some of the other new functionality we've found, we've added, sorry, in iOS 4, beginning with regular expressions. Regular expression has long been a requested feature and now we are getting around to adding it. The new NS regular expression class represents a regular expression. Basically, you can think of it as compiling the regular expression if you've used other regular expression APIs.
So we have in this example, a new regular expression being created with the pattern of ..d, that is any character followed by any character followed by d and that will be our regular expression. So that regular expression will match any two characters followed by the literal letter d.
Well, what do you do with regular expressions? Well, the most important thing is you find matches to the regular expression within a string and so in this example, I have a string called, with the contents good food today and I'm going to look for matches for my regular expression pattern in this string.
So I ask the regular expression for, to return me the matches in string options and give it the range, in this case the entire range of the string. And what does that return me? Well, that will return me an array with three matches in it and here I've shown the regular expression above the resulting matches within the string.
Well, how are these, what's in this array? How are these matches represented? Well, we do that by using a new, another new class which is NSTextCheckingResult. So the array will contain three NSTextCheckingResult objects and these objects represent the, describe I should say, the overall range and the ranges of capture groups. Capture groups are an advanced functionality of regular expressions that I can't go into today.
Well, instead of getting an array back with a list of all the matches, you can with a block and this new block-based API, enumerate through all the matches of a regular expression in a string. And so that's what this new API is for and it also gets passed in NSTextCheckingResult to represent, to describe the range of each match and some additional bits of information in the flags.
The second most common thing that you do with a regular expression is you replace the matches that have been found. Well, one of the new methods, not all of them but one of the new methods that allow you to do that is this new string by replacingMatchesInString method. This takes a string that you give it, that's the first argument there and will return you the new resulting string after all the regular expression matches have been replaced with the template.
Now it's called a template because it's not simply a literal string that you can replace in, that you can replace all the matches with but if you are using capture groups and that functionality within your regular expression, the template can also be used to, you know, say where you want each capture group to be substituted. But in this case I'm not using capture groups.
I'm just using a very simple regular expression and I'm going to replace with a very simple string #. Now I don't know why you'd want to take the regular expression like any character, any character, d and replace it with #, but if you do that, you get something like this and a g# f# #ay.
Well, and a string also has some new convenience methods on it that allow you to access the regular expression functionality that's primarily embodied by the NS regular expression class. The rangeOfString method now takes a new option called NSRegularExpressionSearch and that says to the method if you pass that argument in or that option in, that says to the method, hey, the pattern I'm looking for is actually a regular expression not a literal string.
And that was actually added in, if you were paying close attention to the iPhone 3.2 SDK, that was actually added in 3.2. That also applies though to 4.0, of course as well. The new option also applies to all the find and replace methods in iOS 4 although it didn't in 3.2.
Now that's all I can go into as far as regular expression although that's a very interesting topic. So if you want to know more, I'm going to have to pass you off to Doug Davidson who's giving an Advanced Text Handling for iOS, I guess that should say, talk later today, this afternoon at 4:30 in the Nob Hill Hall.
So what are some of the other changes that we've done in Foundation? So I'm going to do some surveying of some of the more interesting changes. The first is delegate, I want to talk about delegate protocols. Historically, we used to describe delegate protocols, that is the methods that a delegate object could be sent by using a category on NSObject.
So you would see this kind of thing in the header, where there was @interface NSObject followed by the category name and then a list of methods and that was supposed to document the methods that a delegate, in this case an XML parser delegate, could receive. Well, we've switched that to using formal protocols in iOS 4. And so now what you see in the header is a @protocol declaration, in this case for a protocol called NSXMLParserDelegate.
And again, with the list of methods that the, you know, delegate can receive, most of those methods being optional methods. Occasionally there might be a required delegate method that you have to implement but usually delegate methods are optional. We've also updated the types that the delegate method returns and the set delegate method takes as far as the, you know, what the type of the delegate is. So this is telling the compiler, hey, check to make sure that the delegate, that this person setting on this object actually conforms to the new protocol.
Well, what you may have to do in iOS 4 then is update your delegate objects to conform to the new NS, well, in this case, NSXMLParserDelegate protocol. Of course, every delegate has its own protocol but you might get compiler warnings that you can only shut up by making, declaring that is the delegate as conforming to the protocol. In NSPropertyListSerialization, we've introduced some new methods that return NSErrors.
The older methods in NSPropertyListSerialization which allow you to parse and create flattened property lists, the older methods used to return NSStrings by reference as errors. So the new methods return NSErrors by reference, if there's an error and this allows much more rich error information to be returned to you.
We've also introduced new stream-based methods so you can pass in say an NSInputStream and have the NSPropertyListSerialization class parse a property list off of the stream. In this particular example, I'm going to use the propertyListWithStream method, I'm passing there and NSInputStream which I've created and opened and so it's got the contents, presumably has the contents which should be parsed, you know, ready to go.
And I'm going to, you know, let me pass in other arguments including the pointer to the error that should be filled in non-error and if I get back non nil from this, everything worked. But if plist is still nil after this method returns, then there was an error and I should go off and look at the error argument or the NSError variable that I passed in.
NSData has a new method. Just like you can search for a string within another NSString, now you can search for bytes within NSData and you can search for one data within another data. Just like with string, where you can search for a string, you can pass in a few different arguments, or I'm sorry, a few different options as one of the arguments.
In the case of data, we support the Backwards and Anchored options, Backwards of course allowing you to search from the end of the data to find matches and Anchored allows you to, say, hey, only tell me that there's a match if the match occurs at the beginning or in the case of backwards, at the end of the data.
NSString has a new compare method. I actually used this in an earlier example in the talk, localizedStandardCompare. We've added this method in order to encapsulate what we consider to be the standard comparison of the system, if you will. So if you want to sort something in the UI, usually it would be sorting for the, you know, UI presentation to the user, you could use this new method to compare your strings.
Now the exact behavior of this method is not strictly defined because we, of course may want to change what we consider to be the standard system sorting behavior from release to release. So you can't use this if you really need to depend on a specific sorting order. What you're using this method for is if you want to match what, you know, say Apple's apps are showing when they present sorted lists to the user.
NSAttributedString is a new class that we've added. We actually added this in iPhone OS 3.2 but it's still there of course in iOS 4 and NSAttributedString represents a string plus ranges of attributes that apply to various chunks of the string. The easiest way to think about this is in terms of say mark-up text. In this particular example that I'm going to show you, I'm going to use various text and font attributes.
So I have a string here, which is this text is green and bold and the last half of the string has some sort of green text color attribute added to it. I don't know what that attribute is. I'm not going to define any such attribute. You just have some sort of attribute which has changed its display to be green.
The last word, the word bold has had, has some sort of bold font attribute added to it or applied to that chunk of the string and so the word is also appearing in bold as well as green. So you can see the ranges of mark-up can overlap as well and so that's what NSAttributedString is for. Another class that we've added is NSFileWrapper. NSFileWrapper exists in the AppKit over in Mac OS X where we've brought it into the phone and, but added it to Foundation.
File wrappers are generally used to represent a collection of files as a single file or as a way to group multiple files together. For example, you have a directory which contains multiple files, the main primary document file along with a set of subordinate files which are like associated somehow with that main document so that for example, as I say here, images.
So if you have a document with some associated images that, you know, go with the document, you can group them all together into an NSFileWrapper directory and use NSFileWrapper to access those. One of the key advantages of using an NSFileWrapper and any file wrapper API is that it offers fast incremental saving of a document. So if you've only changed say one file within a document, NSFileWrapper document, and you need to resave it, the saving is much quicker than rewriting all of the files.
NSOperation has had a few new methods added to it. For an NSOperation, now you can wait until it is finished, if you really need to. What this does is simply blocks the current thread, waiting for the NSOperation to go into its finished state. Now as with all blocking, we caution you against using this without some careful thought because any sort of blocking can ultimately involve, you know, chains of things blocking against one another and thus deadlocks.
If you want, another thing we've added to NSOperation is if you want to have some block of code run when the operation finishes, we've added a convenience for that, a new property where you can set a completion block and after the operation goes into its finished state, this block will be executed.
So that can be a convenient way to say do some final work for the operation or to start new operations as a result of this operation having been finished. We've also added a new subclass of NSOperation called NSBlockOperation. Just like NSInvocationOperation class takes an NSInvocation to execute as the work of the block and NSBlockOperation takes one or more blocks to execute.
And those blocks become the work of the operation, when those blocks are all done after the operation has been started, when they're all done then the operation goes into its finished state. So this is a convenience method to create a block operation with a block but you can also add many blocks to an operation, a block operation.
If you add many blocks, all those blocks are going to be executed concurrently and so this is a way to have an operation do a kind of little fan-out of work across multiple cores by executing multiple blocks simultaneously. When all of those blocks have finished, then the operation as I say will go into its finished state.
NSOperationQueue in iOS 4 has been re-implemented in terms of grand central dispatch or GCD. Now I, unfortunately, I don't have time to go into GCD today but there will be another talk tomorrow on grand central dispatch if you're curious about that. Two new methods that we've added to NSOperationQueue are operationCounts and addOperations:waitUntilFinished. What we've found for the first one that a lot of people were asking an operation queue for its list of all its operations and then just asking that array for its count, to get the count of operations in an operation queue.
And then they were throwing, of course the array away so rather than do all that work to create the array of operations, we provide direct access to that piece of information now via a new method. The second method there allows you to add, do a sort of bulk add of many operations at once and if you wish, you can pass in yes to the waitUntilFinished argument and this method will wait until all those specific, those specific operations that you added have finished.
Because, you know, we've added a lot of block API, of course, we felt that we should offer a convenience method to add a block to an operation queue so you don't have to create an NSOperation object and so we offer a new convenience method, addOperationWithBlock. And it takes a block, if the block doesn't take any parameters, it doesn't have any return value. It's just a chunk of code to be run and eventually that will, you know, percolate through the operation queue and be executed by the operation queue on some thread rather.
We also added two new special queues to the system. The first is we've added a method to return the current queue. Well, the current queue isn't any particular special queue but when code is running within the context of an NSOperation, that is an NSOperation is calling some code, well, that NSOperation has a queue. And so, this method, currentQueue will return non nil. It will return that queue that the code is running in when that code is running in the context of an operation queue.
Of course, you might have a method which can be called outside of an NSOperation and then this method might return nil because it's not running in the context of an operation. But this can be a useful way to get a hold of the current queue if you, you know, need to do some more work with the current queue.
The second new method is mainQueue. The mainQueue does represent a special queue. It's a special queue that only executes its operations on the main thread. Of course, because there's only one thread involved, that is the main thread, this is a serial queue. And so you can use the mainQueue method to get a hold of a queue which will execute its operations on the main thread. So this is a way, a new way to execute stuff on the main thread if you need to.
Well, one place you sometimes need to execute code on the main thread is in response to notifications and so what we have here is a new method that allows you to pass in a block as the observer essentially of a notification. So in the last argument position there, we have the block. The block just gets the NSNotification object and essentially what you do is you're asking the system add an observer to the notification center for me using this block and the system will do that.
The system then returns that observer in effect in the return value, that is the return value being id here. This is the observer essentially that the system has wrapped the block with and is returning to you. So the return value in this case is retained by the system so as long as you don't remove this observer from the notification center, the block will receive the notifications, the notification name that you've asked for.
To remove or stop the block from getting called, you need to use the removeObserver method with that return value as the parameter to removeObserver in order to unregister, that's cancel the registration. The third interesting thing about this new method is that strange queue parameter. So you can pass in nil to this parameter and nothing different will happen from the existing addObserver method that you might already be familiar with. But if you do pass in non nil, that is you pass in a valid NSOperationQueue, what will happen is that when it, when that notification is posted, your block that you've passed in here will be executed on that queue, or in the context of that queue.
Essentially what will happen is the NSNotificationCenter implementation will say oh, you know, this block needs to be invoked. This notification is being posted and here's a block that needs to be invoked. Well, the block will simply be thrown on the queue by the NSNotificationCenter implementation and then the block, or the notification center will continue looking for more observers to notify.
So what happens is that queue arguments open up the possibility for asynchronous handling of the notifications or also concurrent handling of notifications, that is if there are many different observers registered with a block, they might all end up having their block run simultaneously on different threads, you know, to do their handling of the notification.
But posting, that is the, there is a thread which is posting a notification and of course the observers have to receive the notification. The posting thread is still blocks in the posting operation until all the observers have completed their handling of the notification. So even though the block here is being en-queued off on a queue and eventually will percolate through the queue and then ultimately get run by the queue, hopefully that happens quickly but not necessarily. The posting operation still has to block waiting for all of the observers to have handled the notification, to have seen it before the posting can continue and return control to you.
Other changes that have occurred in Foundation, well, in NSDateFormatter, we've added two new bits of long-requested functionality. The first is that given a set of components that you want a format string for, we now have a new API that will return you an appropriate format string given those components. So currently, we offer these different styles, you know, short, medium, long, and full styles for formatting dates.
But sometimes you have a specific set of components which you want to appear in your format strings, in your formatted dates, but you don't of course want to depend on the short format always, you know, say providing those specific components that you wanted, or the medium format. Those things can change over time. Instead, if you have say in this example, I want to display the month and the day and the hour and the minute.
So I specified the format specifiers Mdjm and of course, you may say j, well that's not an hour specifier if you're familiar with NSDateFormatter. J is a special character that says well, I want the hour in there but I don't know whether I want 24-hour or 12-hour. Just give me whatever is appropriate for the locale. So j is a special character for this particular method.
So having asked for, now my locale is U.S. English when I run things on my computer so what I get is a date format which is the U.S. English form that is the one that contains month and days, hours and minutes. You notice at the end that there's an a. The a is the AM/PM designator and it gave me the 12-hour h-format specifier. So even though I didn't ask for the AM/PM designator, the method is smart enough to add it in there because it knows it should go with the 12-hour hour format specifier.
Well, once you have one of these format strings, typically you turn around and you set it in a date formatter in order to format your date so in this case, I've set it in the date formatter and I'm going to call stringFromDate with the current time and if I'm on schedule for this talk, the current time is around 11:02 AM on June 8.
The other interesting bit of functionality we've added to NSDateFormatter is yesterday, today and tomorrow formatting of the date so rather than say, you know, always saying 6/8 is the date, which is today, the text today for, you know, U.S. English would appear. Of course, if your user is running in, say Japanese locale or Thai locale or what have you, you know, of course the appropriate thing for that locale would appear.
So if you have say dates which are appearing like this normally, instead if you turn on the doesRelativeDateFormatting property, what you'd get would be something like this. And of course, don't assume that a locale has three special dates that is today and then the day before and then the day after today. Some locales actually have special formatting for today plus or minus two days or plus or minus three days so it's not always just today plus or minus one day where special formatting might occur.
Finally, we have a new class called NSCache in Foundation and this is a class to help you with caching of objects. Now sometimes you have some expensive objects, objects that were expensive to create and you want to keep them around but you don't want to induce so much memory pressure that you're app is going to be jettisoned for example.
So NSCache will discard automatically some of the older or least recently used objects if there's memory pressure. So while an NSCache is like an NSDictionary in that you put objects in it with said object for key and you get objects out by using the objectForKey method and the objects are still retained just like in an NSDictionary, if there's memory pressure, the objects may disappear from the cache automatically. The other interesting thing about NSCache is that NSCache is naturally thread-safe and so you can access them on multiple threads safely, simultaneously.
Well, that brings me to my conclusion. So I talked a bit about blocks. I've introduced blocks and then a bunch of other of the new Foundation API changes. Now, I didn't, I wasn't able to go into a lot of the more interesting things about blocks within this short time. For example, I didn't talk at all about block life cycle, where blocks live in memory and how you hold on to them and how you destroy blocks.
So you have to go to the documentation to get more information on those things or there's also some links, if you want to find out more about some of the other API changes that have occurred. There are some links for this particular session in the session database, some bits of, you know, information like the complete API dif have been linked in there, if you go to say the developer.apple.com website and look at the information for this particular session.
So there are some related sessions which are interesting and I want to point out. Now, at 9:00 AM this morning, there was a What's New in Cocoa session over in Mission here. If you missed that, you may want to catch the repeat of that. This particularly focuses on Cocoa Touch and what's new in Cocoa Touch on iPhone OS, iOS 4.
I've already mentioned the Advanced Text Handling talk later today at 4:30. If you want to know more about Objective-C or delve more into Objective-C, there's an Objective-C talk in Pacific Heights tomorrow at 9:00 AM. If you want to know more about blocks or grand central dispatch, there's an Introducing Blocks and Grand Central Dispatch on iPhone talk tomorrow at 11:30 AM in Russian Hill.
Now, because this of course is a new, is a major update to Foundation, you might find yourself being burned by assumptions you made about how Foundation APIs behave and so if you do find yourself having been burned, one talk you may want to go to, to maybe find out some more things about how it can be a little bit more perhaps robust is the Future Proofing Your Application talk on Thursday at 2:00 in Pacific Heights.
Finally, there's a related talk which will talk about some of the API decisions and some of the naming patterns that we've used in Foundation called API Design for Cocoa and Cocoa Touch and that's in Marina on Thursday at 4:30 PM. And that talk may give you some insight into, you know, why we have adopted some of the kind of conventions and what the conventions are that we've adopted in creating these Foundation APIs.