WWDC2010 Session 102

Transcript

>> 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.