Frameworks • iOS, OS X • 53:57
Learn from the experts about the Cocoa and Cocoa Touch classes you may not even know exist, as well as some very obscure but extremely valuable classes that are favorites of the presenters.
Speakers: Scott Stevenson, Mattt Thompson
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
So many people, this is awesome. Thank you very much for coming out. So, it's Friday, as you probably noticed. And, you know, 'cause it's Friday, we thought we'd do something a little different, have a little fun. You all got the note that today is Audience Participation Day. Did you saw it in your-- I just made that up. But, no, seriously, audience participation. So the first thing, if you'd help me out-- by the way, my name is Scott Stevenson. I work in Apple Engineering.
Thank you. So, if you would help me out, just by show hands, how many people here today consider themselves sort of beginner, just getting started with iOS or OS X? No beginners, really? Two, three, OK, all right. We're going to see-- you think you're really good, but we'll see.
So-- And who considers themselves sort of like intermediate, like pretty good but not total expert? Wow, OK, all right. See now, we're being honest, OK. What about like total expert, like people there's no way you're going to learn something, you're just here to like heckle the other guys? OK, all right. So you guys are going to learn something. So, here's my-- here's the deal.
My goal is to make sure every single person in here learns at least a few awesome things. And the AMB guys and the first two groups, you guys-- your job is to watch the other guys. And if they learn something, 'cause I'm going to check later, then I want to hear about it.
So, the first thing I want to say here at the beginning is how many of you know about NSHipster.com? OK, yeah. So right, so you guys know the deal with this. But just in case you don't, the thing here is that the author, Mattt Thompson, what he does is he goes out-- and of course, Cocoa and Cocoa Touch are these really like expensive rich frameworks with so many things available, and you're-- it's likely that because there's so much stuff, you're actually going to miss some really cool things.
So, what Mattt does, he's been doing this for a while, he goes out and digs up these really, you know, amazing gems hidden in Cocoa and Cocoa Touch and brings them to the surface and says, "Hey, you guys really should be using this 'cause it's awesome." So we ran across the site and we said, "Well, this is super cool. Let's do a session on this," you know, 'cause that seems like a really good idea.
And so, we called Mattt and we're like, you know, "Would you want to come up WWDC and talk about it?" He's like, "Sure, that sounds good." So we actually brought him today and I'm going to bring him up in a little bit, but I just want to call this out in the beginning and just, you know, give credit where credit's due that this is sort of based on something Mattt did. So, we have 30 tips.
So remember the expert folks that appears you're not going to learn anything, remember below of averages, pretty good chance you're going to learn something and you're going to see them counted down as we go. So, here's the little map here that we did. We have a graphics team as you can tell. And-- So we're going to cover a bunch of different frameworks. We're going to start at Xcode, Objective-C, and then kind of work our way up to the different levels. And we'll eventually end up on-- I guess that's like AppKit Peninsula or something like that.
So let's start with Xcode and we're going to focus on editing and debugging to start. And we're going to kind of start with some more basic things and work our way up to the advanced stuff. So to start, if I can get the clicker to work, there we go. So, I'm sure a lot of you are familiar with the feature in Xcode called Open Quickly, and you just bring it up by going to the File menu and choosing Open Quickly of all things. And you can also just hit Command-Shift-O.
And what happens is you choose that and you see a window like this pop. This is Xcode 4, of course, so, you know, it looks a little different than Xcode 5. But this window comes up and then you just go ahead and start typing something. And what Xcode is going to do is it's going to look across all the code in your project and all the frameworks that you brought in, and it's just going to start live filtering results.
And I'm sure a lot of you are actually familiar with this feature. If you're not using this, you definitely should be using this because compared to like Project Search where you have to type something and look at the long list result and say, "Ah-ah, that wasn't quite what I wanted. Let me delete it and do it again," you're live filtering stuff in Open Quickly. So you should be using this like all the time, all day.
But the thing you may not know is that it's actually pretty incredibly smart for what you're searching for. So, in this example on screen, I've typed coretextctpar, and Open Quickly is smart to say, "You know, I think what you actually meant was the CTParagraphStyle header in CoreText," so it splits that up. So, another example is you can type in abbreviations. So you can type in UK/UIVC, and again Open Quickly is like, "You know what, I'm pretty sure what you actually meant was UIViewController." So, it's going to go ahead and highlight that.
There's other options, but that's the one that pops up to the top. Next tip-- by the way, since we have 30 tips, we've got just about an hour, I'm going to have to race through this in case that's not clear. So next tip, this is one of these things that I see my coworkers everyday using and every time I see them using, I'm like, "Why am I not using this? This is so useful," and that I'm just wasting time. They're like done and I'm like going to lunch.
So, all you have to do is in the upper left hand corner of the Xcode Editor pane, there's this tiny little, really not super obvious button but incredibly useful called Related Files. So if you click on it, it pops up and shows you files that are related to the cluster you're currently working on which is a great thing for-- to you based on what I'm saying.
It shows you Subclasses, Superclasses, Categories, and one of the most useful items actually in here is the Callers and Callees. So, other classes that are calling this class and other classes you call are actually listed in that menu item. So you should always be using this all the time, [inaudible] thing here so I remember to use it so I'm not wasting so much time.
Next trick-- and this honestly is another one of these things where I wish I'm really just putting this here so I remember to use it. So a lot of times what happens when I'm debugging something is I'll get kind of halfway through my debugging session and I'll be thinking, "Boy, if I got just one thing I need to actually have here to help me through this problem," and so I'll like typing in NSLog and stop and recompile, and then I'll be like, "Why didn't I use Breakpoint Actions 'cause this is so much better?" So all you need to do to use Breakpoint Action is go to the line of code where you need to log some additional information, just pop in a breakpoint.
And if you right click on the breakpoint, it will pop up this popover. You can do a bunch of things with this just pop over, but the one thing I just want to highlight here is that you can actually just add a log message. So, just use Log Message, type in whatever the format string is that you want. And you can actually do some pretty cools things with conditionals and the number of times to skip the breakpoint.
But anyway, you can type in a log message and you don't have to stop running the program. It can just keep going, of course, 'cause this is a breakpoint. So, do not-- from this day on, do not stop and write NSLog and recompile, just use this 'cause it'll save you tons of time.
Debug description, just a really quick one. I'm sure actually a lot of you, hopefully, are aware of this. So of course there's the description method that you implement on your classes just to see something in the console when you use NSLog. But debug description is a little bit different.
So it's intended to be kind of more provost debugging string that gives you extra information that you only really need at debugging time. So it just looks like this. This is not rocket science. You implement a method called debugDescription. You return some ridiculously long string that you think you might need to print out for some reason.
And then when you're in lldb or in the-- just in the Xcode visual view and I do a po on self.rootViewController here, I get that really long string. So of course, you're not getting the normal just description which you may be using for other purposes, it's just for debugging.
And these are for Breakpoint Actions, that's obvious, OK. One more quick hit in case you guys are not familiar with it. There's a method you can call called recursiveDescription on View Hierarchy, and it will give you back something like this. So you can actually see the complete layout of your View Hierarchy just sitting there on the debugger which is ridiculously useful, so you should be using this. OK, [inaudible].
[ Pause ]
How are we doing? Are we learning stuff already? Did somebody learn anything? Hands. OK. Just wait, there's more. OK, so we're going to work our way up now. We're going to look at Objective-C stuff. So, just a quick refresh on what Subscripting is. I don't-- I think most of you are probably using it at this point. But it was something really nice added in-- recently to Objective-C. So a typical use case here is I have an NSMutableArray called in indexedValues.
And using the new subscripting syntax which is, you know, very common to people from other-- or very familiar, I should say, to people from other languages, you can just use this nice little bracket thing. So don't have to say like objectAtIndex, you just say in bracket zero. You can give values out, set them. That's all totally straightforward.
And of course, you can do the same thing with dictionary. So that's just a little review. That's not the actual tip. The tip is that you can add this to your own classes. And I'm pretty sure most people based on who I've talked to don't actually even know you can do this.
So, here's how it works. I'm going to make up a fake class here called Record Set and I'm just going to add a property here called indexedValues. You could have anything [inaudible] as much as here, and you got two methods. So the first one is called objectAtIndex subscript, and you can actually see this declared in NSArray. And then the setter, you don't' actually need the setter. But if you want the setter, you implement setObject:atIndexedSubscript, and then I'll just close up the class like that. But it says-- oops, jumped a little ahead there. Oh that's OK.
But just those two methods that back this, and then the implementation is just whatever you want to do to get that object to that index. In this case, I've just looked at my indexedValues property and pulled out the value and I set in the setter, and here's how that looks in use.
So I'm making-- just an instance of my fake record set class here. And then after if it's initiated, I can just use this subscripting syntax directly on my class which is pretty cool. You could imagine this would be-- I called it records out here just to kind of suggest it might be kind of cool for like a dataset coming from a database, that sort of thing, you know, so I can set it and get it, not super rocket science. And you can do it for keyed subscripting too. So, it's going to look very similar to the last example. In this case, I made a person class.
And actually I'm backing it this time by a dictionary. But again, it doesn't have to be backed by a dictionary or an array. It can be anything that you need to accomplish a task. So again, there's two methods, objectKeyed [assumed spelling] subscript instead of index, and setObject: forKeyedSubscript.
And these also are declared in NSDictionary if you just want to copy and paste them. So it's just those two methods you need for the declaration. And the implementation is really not very surprising. Again, you're just using the regular dictionary method set and get the objects. So, that's pretty straightforward.
And here's just a quick little example of how it works. You say, you know, person favorite color, and you might be kind of wondering, "Well, why not just say person.favoritecolor?" This is a literal string, but you can imagine a scenario where you're fetching something from a service or you're pulling something out of a database, and you may have actually know those keys ahead of time, so this will be a useful way to kind of to simply, you know, put those values and get them back out.
So, that's pretty cool. But, hey, you know what would be really cool is if you can actually use both at the same time. So, I heard some clapping there, that's awesome. So, I have just one more fake class here called Ultra Record Set because it's inappropriate. So, I've got indexedValues and keyedValues, and this is-- you know, I bet you can see where the plot is going here, objectAtIndexedSubscript I implement both of the indexed ones, I implement with the keyed one, close it out, it all just works, so you would expect. And then, of course-- let me get the clicker to work.
And of course, I'll just make an instance of this and I can just go ahead and start setting, getting those values the same way I did before. So, all that, you can just go home and use that and have fun with that. OK. A few quick things, so these are-- everything so far as being kind of additive. This is reductive.
So in versions of Xcode prior to 4.3, and really just like the entire lifetime of C, if you wanted to call a method inside of-- like a private method inside of a file, you would have to declare it somewhere 'cause the compiler would like somehow not be able to figure it out. But guess what, since Xcode 4.3, you actually don't need this anymore. So, if you have a private method that you're calling from within the same file, you don't need to declare it. The compiler will figure that out, so that's good.
And this is-- maybe more of you are familiar with this, but since Xcode 4.4, you would-- you can of course declare properties. And then in earlier versions of Xcode and Objective-C, you would then synthesize the accessor if you wanted to set and get those values automatically, if you want the compiler to make the accessors for you. Since Xcode 4.4, you don't even need this anymore.
So, go delete all that, we did/ so I recommend that, [inaudible] your code. OK, so as I promised, we pulled Mattt Thompson out from the NSHipster hole or whatever it's called, NSHipster Cave, I'm not sure what it's called. And he said he would come up and show off some cool things. So, I'm going to bring Mattt out. Thank you.
[ Applause & Inaudible Remark ]
Hey everybody. Good morning. My name is Mattt Thompson and I am an NSHipster. And today, I'm very excited to show you some of those Xcode tips that Scott just told us about, and my favorite new addition to Xcode, something called Instance Type. So, let's switch over to this.
All right, you can see code. All right, this is a very simple project. We have an employee class. Well actually, let's use Open Quickly employee.h. There we go, pretty nice. We can also use our assistant things, so we can see the .h and .m on the same view. Pretty simple, we have a name and a salary.
But here, we have a common pattern. It's a class constructor, convenience method that returns an instance of an object initialize with, in this case, a name. This is just a short-hand for alloc-init and setName. The thing here though is that we have ID as being the return type. So, let's kind of illustrate what kind of problems you can get into with that. We'll go to main.m. All right, let's say we have employee, employee with name, and I'll employ myself, all right.
Here, you know, Xcode is-- doesn't have any sort of idea what kind of objects returned. It just knows that the returned type is ID. So, I could do for instance add object. What? That doesn't make any sense. I can build and it's not going to complain. It's going to say it succeeds. But of course if I build and run, and I'm going to get immediately, you know, [inaudible]. That's terrible. So how can we improve on this? Well, up until recently, kind of the suggested pattern might be to let's say, OK, go to-- back to employee.
Instead, return just an instance of employee, right? So we have our employee object. We would change it in our implementation as well. And then if we go back to main.m, if we have this method here, let's say add-- well, it's doing add observer. So we know that it's not responding. It knows to narrow down the selectors to only NSObject and employee.
But let's say, you know, I give myself a permission. We have a manager class too. So manager is a class, no real implementation here, just a new property, subordinates because I have subordinates, I'm a powerful man now as a manager. So-- And again, we don't have to, you know, synthesize our property. So back to main.m, say it's manager, so I'll make myself a manager, and I do set-- well, setting salaries is kind of cool. I'll keep that one for later. If I do set subordinates, you know, it's not completing, darn it.
No, no, OK. So, what's going on here? Well, manager-- employee with name, that's for turning an employee. What I want is manager. But if I went back to ID, I'd still be, you know, you understand where this is going. So, we have something called Instance Type. If we go back to employee, we change this to Instance Type. It's sort of the Goldilocks kind of return type. It is the flexibility of ID, but you still get the type inference of kind of doing an explicit declaration of the return type.
So in this case, it's saying, "I will return whatever class kind of called this." So, if we go back and make sure to fill out our implementation as well and then back to main, now if we do this, I can set subordinates. Hey, check that out. So Instance Type, it is the perfect kind of way to do class constructors.
And you'll notice that in the API divs for iOS 7, Mac 10.9, there's a lot of methods. Although previous class constructors that were using ID like NSArray array, they're all now using Instance Type. So using your own code, clean it up, it's really a convenient thing, and I'm going to pass back to Scott. We're going to talk about some Foundation stuff. So, yeah.
[ Applause ]
All right. Learning things, all right, OK. So, move on. So we're going to talk about Foundation. So we've worked our way up from Xcode and Objective-C, and now we're getting into the frameworks. And for the most part, everything we talk about for the rest of the talk and really everything we've talked about so far applies to both iOS and OS X. So everything for iOS 7, everything from Mavericks, all these should apply. So you can keep that in mind. We have some iOS specific stuff and AppKit specific stuff at the end.
OK, so Foundation. Let's jump on to this. So, a lot of you I'm sure are familiar with Grand Central Dispatch. This is great technology we added a few years ago that allows you to breakup work into individual work units and distribute them across whatever resources are available on the system, so it's really great.
But I don't know how many of you are actually familiar or are using NSOperation. It's this really great object-oriented API that sits on top of Grand Central Dispatch. So, all that really super cool performance stuff that you get from Grand Central Dispatch, NSOperation offers with all the Cocoa Objective-C goodness.
So, in addition to that really nice API, it also has some features that are unique to NSOperation that you can't just-- you can't get using just Grand Central Dispatch. So, for example, you can cancel queues. So, you can have stuff running out there and you say Cancel and it will stop running. I mean if you're subclassing, you have to do that in your side as well, but it's available to you. You can also set max number of concurrent operations at the same time.
So, you might have tons and tons of hardware and you say, "Well, a hundred concurrent operations is fine here. But if you're stilling it down to a mobile device, I might say, well, maybe four concurrent is good." And you can set up dependencies, and this is super cool.
I'm going to show you an example of this in a second, but you can actually take different work units and say, "I really do not want this one to even start until the thing it depends on has completed." And of course, I mentioned Objective-C APIs, so that means you can subclass it, you can add categories to NSOperation, and you can use even key-value observing to monitor the state of the operations as they're running. So, it's a great way to cleanup your code and use for a-- sorry, build a more robust source base.
So, here's a really good example. I'm sure a lot of you are actually familiar with this app. This is the WWDC app running in iPad and we used NSOperation here in an interesting way where you may actually anticipate. So we use the Dependencies feature in NSOperation to specifically make sure that any time we go do a request to the server for things like to fetch your favorites, to find out which sessions are currently available or to get the information on session, we set up a dependent operation that first authorizes the user.
So, anytime we go out and do that feed, before we actually launch that operation, we set a dependency on the authorization. So, here's what it looks like. This is code, it's almost directly from the source base, so I cleaned it up a little bit so it fits on the slides, but it's pretty much true to form.
So, just walking through this, I have this method that says addDependencies ForAuthorizedOperation. I'm creating these authorization operations, sounds like Dr. Seuss. And then I add it as a dependency on the operation being passed in. So might be passed in, for example, like set of favorite. And then I add the off operation-- author-- off operation to the operation queue, and that's all I need to do here. And then I have the zipper method which is setFavorite.
I create that operation. I instantiate it with the block I'm going to use. Set favorite status, and then I call this method I've defined. So, if you think through this, it means that anytime that we want to go ahead and do an operation, I just call, set the method and says, "Whatever you do, just make sure that the user is authorized before you go do this." So it's a great way to kind of cleanup that logic and make all these independent work units work together for you.
And add to queue of course. OK, NSExpression. So, I'm sure a lot of you are familiar with NSPredicate which is used in Core Data and it's used in different places if you're filtering arrays for example. But NSPredicate is actually built up by individual constituent parts in NSExpression. And this thing is really cool. I'm going to show you.
By the way, this is one of these things, when we're working on the session, there were four of us working on it, and every one of us, when we were trying to brainstorm the ideas, we're like, "I didn't know you could do that." And we've accessed the source code and we didn't know that. And this is one of those. So, NSExpression can actually parse mathematical expressions.
So here, I've got 3 plus 5 times 4e10. And if you've ever messed around with this spotlight menu in the upper right hand corner, you've probably discovered you can actually type mathematical expressions in there. So this is that same thing. And this is actually pretty flexible. I was blown away when I was trying it yesterday, square root, you know, syntax, all that kind of stuff.
So you just say NSExpression WithFormat, you pass in your text, of course you can pass in a variable if you want, I didn't in this particular example. But then you just evaluate the value, print it out, and then you get this really, really big number. So that's pretty cool.
So you can imagine, if you wanted to have the user type in some sort of mathematical equation, you wanted to show them the results, so there's going to be a bazillion math apps now, I'm sure, but that's actually available to you if you want. It's going to be the new flashlight. OK. So-- yeah, flashlight fans, yeah. It's a great app.
OK. So, in addition to our friends, NSArray and NSDictionary that we're using all day long, you should also be using NSSet, NSOrderedSet. And there's some very specific scenarios where they work really well. If you're not familiar NSSet, OrderedSet, you don't really know the details, basically one of the key things they do is they guarantee uniqueness.
So with an array or a dictionary, you can have multiple instances of the same object or, for example, like two NSNumbers of the value of 2, you know, you can have those across the entire-- you know, multiple instances of those across the collection. But NSSet and OrderedSet guarantees you'll have a unique one instance of a value throughout the entire collection.
So, the other thing it does that's really great and in particular for NSSet is if you need to check to see if it-- like, for example, an object has already been loaded into memory so it uses as a cache, checking for membership in an NSSet is practically free. So there's absolutely no reason to not use it for that sort of thing. And I actually just talked to somebody in the labs yesterday and they were blown away that this was so fast. So this is really, really good.
And there's also something interesting you can do with set calculations that are not available on array and dictionary. So here's an example. You can do intersectsSet, so you can take one set and another set and see, you know, do they intersect. You can say, "Is this is a complete subset of the other set?" You can do a -minusSet.
You take one set and just remove the entire contents of the other set. And you can union them. So this-- on the surface, it says, "Yeah, yeah, that's great," but think about that. That means that you don't actually have to loop through the arrays and do all the stuff yourself. You can convert them to sets.
You'll guarantee that they're all unique. And then when you've actually run these operations, you'll going get the final set of the thing you need. So this is really, really good. The one thing just to keep in mind is before you go converting all your NSMutableArrays to NSOrderedSets, NSMutableArray is faster at adding objects. So if you just need to add a lot of objects, continue to use that as MutableArray and you can switch back and forth when you need to filter them. All right.
Oh also, I just want to mention, there was a talk right before this one, I don't know if you were in the room, but you should catch on video if you didn't see it, Designing Code for Performance, so Quinn gave that. And it dives into how to use the Foundation collection classes to have really, really fast codes. So you should definitely check that out. OK, so a few quick hits here for different collection things you may not be familiar with. We'll just kind to go through this real fast.
I see 11 on this slide. It really should count for like 15, so. So, reverse arrays inline quickly. So I just have an array of numbers here and if I call reverseObjectEnumerator, usually when you get an enumerator from array, you're going to look through it. But in this case, I'm just sort of borrowing one little method from it which is numbers.reverseObjectEnumerator, we should get the reverse order, and then I just call allObjects. So we don't actually have to loop through that. I'll just get the complete set of reversed object. So that's good.
A lot of times, when you're implementing a method, you're passed in some sort of value and need them mutate that array or you need to mutate that dictionary. And a common pattern that I see is you may want to check to see if that value you're being passed in is nil because if you call mutable copy a nil, you're going to get nil back. So that's not really helpful. So instead of doing that, you can just say NSMutableArray arrayWithArray. And even if it's nil, you're going to get a MutableArray back. And that's a case for most of the collections classes, dictionaries, NSSet, OrderedSet, OK.
Another scenario you might yourself in is you might be passed in one of any number of collection objects. So for example, you might have a method that takes a dictionary or an array. And there's sort of this question about, "Well, you know, how do I declare that? Do I-- is it like an id or an id component to NSObject?" Well, what you can do is just specify id conform to NSFastEnumeration. The only thing you need to do is actually just iterate over it. This is absolutely perfect for that. So that can be almost any collection class that we have.
And, interestingly enough, you can do this on your own class. So again, if you're thinking about that record example that I showed you before and you want to actually enumerate through them, all you have to do is implement this one method, countByEnumeratingWithState, objects count. And it turns out that the implementation is incredibly simple. If you have an array, you just call that on the array.
So, there you go. So, now, I would like to bring up Mattt. And you probably-- when you saw his demo, you might have been thinking, "Yeah, yeah, I knew that." He's going to show you some stuff I guarantee you, you do not know. I did not know it, none of us know it. So, he'll bring that back up.
All right, so Foundation and Core Foundation, two of my favorite pieces of software in the whole world. Let's talk about some obscure stuff. Well, first of all, let's-- at the outset, let's say Objective-C really sits at the interface between the procedural world of C, you know, the really strong foundations, but it also combines that with the object-oriented paradigm inspired by small talk.
And right at that interface is a class and its value. You might be more familiar with its subclass, NSNumber which is in an object representation for things like ints, floats, doubles, and Booleans. But NSValue, you know, still has a few tricks up its sleeve. For instance, it can store all those scalar values but it can also store things like structs.
Specifically, you might be working with structs like ranges or point, sizes and rects. And then one of the other things that it does that actually very few people know about, it can also return unretained references, and I'll show you an example of how you might use that later.
So, another tip. Let's say you're trying to construct an array and you want to have a whole bunch of different, you know, C-values in it, so this is how you do it. So you have a MutableArray using the subscripting here, just adding, you know, values, valueWithPoint passing a CGPoint, valueWithRange that's passing in an NSRange.
Let's say you have a custom struct here, you know, if you don't UIColor for some reason, you just want this RGB triple, right? You have red, green and blue values, and you have an instance to that, you can encode that and put into an array by doing NSValue valueWithBytes passing a pointer to the color, and then Objective-C type using the @encode and then the type of the struct.
Whenever you're using NSMutableDictionary, another kind of collection, you know, it's simple. You do a Key equals Value. That's works really well whenever Key conforms the NSCopying and because NSMutableDictionary copies its keys. That does not work so well for some objects that don't conform to NSCopying. And you might not be able to think of any, off the top of your head, but certainly if you'd gotten into a situation where you're trying to do this and you're trying to figure out why this doesn't work, this is a lifesaver right here, NSValue valueWithNonretainedObject, you pass it in, it will just work magically, just assume that the object is being owned by something else, everything works just marvelously. Let's talk about Key-Value Coding. Key-Value Coding is another really cool feature of Foundation.
You know it, you love it. valueForKey, name, it's an equivalent to emloyee.name. The thing about Key-Value Coding, of course, is it's a way to dynamically set and get properties and also, you know, traverse object crafts too. So, valueForKeyPath, manager.name, that's equivalent to employee.manager.name. All right, you guys already know that. That's not the tip.
The tip here is that you can also do this on collections and by passing in Key-Value Coding, you know, doing that on a collection, you'll actually get the result for each objective in the collection. So here, we have an array of words, Alpha, Bravo, Charlie. Let's do valueForKey, uppercaseString. You get an array of the uppercased words. Or, let's say you do length.
This is actually really neat, right? So, Key-Value Coding automatically boxes and unboxes values into their object representation. Length normally returns an NSUInteger. But in this case, you can see that we have the @5, @5, @7. We have NSNumber representations of that. So, really useful, you stay within the object paradigm.
Another cool thing you can do here. So, it's often the case that you will be making app, especially like iOS apps, you're going to be interfacing with some sort of web service API and maybe encoding, you know, serializing values from JSON into an object. Instead of doing that boilerplateself.name=json [assumed spelling] valueForKeyName, you can use this dictionaryWithValuesForKeys.
And you can-- you know, it's kind of a shortcut for all that-- or sorry, that's the way to serialize it, I guess. So, you can create a dictionary representation of an object using dictionaryWithValuesForKeys, the keys that you want to serialize out, maybe send back to that web service and then pass in that resulting NSDictionary to NSJSONSerialization. And then that setValuesForKeysWithDictionary, that's where you'll be able to serialize your object really quickly.
Really neat. That's just assuming, of course, parity between like your JSON keys and your property names. Let's talk about KVC Collection Operators. You might have seen this in the wild, but may not have had a chance to use these yet. So the most common one you might see is valueForKeyPath and then you say, "Here's a collection colleagues," and then . @count. Some other examples of this you might have, the @avg.salary or the max.temperature.
So there are three kinds of collection operators and they are kind of distinguished based on the different return types they have. Simple collection operators return objects. Object operators return arrays. Maybe a count or two, but it'll all make sense. Array and set operators return either arrays or sets.
And the syntax for this is something that you might find yourself looking often. I know I have this bookmarked in my documentation. You have on the Left Key Path, however to get-- the way you get to the collection itself. So in the middle, you have the dot-- these are all separated by dots.
You have @ and then the collectionOperator itself. And then on the right, if you want any aggregate properties on the result of the collectionOperator, you both head to the right. Again, you'll be looking this up often. It's just one of those things that it takes a while to get into your head.
All right, so Simple Collection Operators. We have, again, count that'll give you the number of elements in your collection represented by an NSNumber. You also have sum and average. So for collections of NSNumbers, it'll give you the, you know, arithmetic sum and average of the numbers in that collection.
I think the two most useful and interesting ones are max and min. These don't work just on numbers. They work on any object that implements compare. So you can have the max and min date, or the max and min weather, or the max and min whatever. It's a really cool and convenient thing that you can add to your own objects and take advantage of.
We have Object Operators. We have unionOfObjects and distinctUnionOfObjects. The difference here is that distinctUnionOfObjects will unique the resulting array. An example of this in code, let's say you want to remove all the duplicate values in array without actually passing it through an NSSet first. The way you do that is that you do array valueForKeyPath:@ "distinctUnionOfObjects.self".
And that's actually a cool tip. You can pass self in for different situations and kind of use these different operators on collection, you know, itself. So, finally, we have Array and Set Operators. You have unionOfArrays, distinctUnionOfArrays, again just like the previous one, and then distinctUnionOfSets. Sets, of course, everything is distinct. So there's no non-distinct version of your-- and the return type is going to depend on what you pass in, arrays for arrays and sets for sets.
Let's kind of illustrate, this is an example. This is for flattening out values within sub-collection. So let's say I have an array with two color schemes here, some beautiful color schemes. If I do valueForKey unionOfArrays, it'll look like that. So it's taking the two arrays-- the subarrays and putting them into one flat array values. Or if I do @distinctUnionOfArrays, we now just have the four distinct colors in an array. Let's talk about NSDataDetector.
So in Mail, you might notice that whenever you have an email message with certain kinds of information, that information will be highlighted. And by clicking on that information, you can very easily add stuff like a phone number to your address book or a date to your calendar. Very convenient. The coolest thing about this is that NSDataDetector is underneath the hood of all this and you can add that to your application too.
So NSDataDetector, it's the sub-class of NSRegularExpression. But instead of passing in kind of arbitrary formats, it has kind of these pre-calculated, really, really complex regular expressions to find dates, you know, relative dates or, you know, any sort of date format, addresses, links, both URLs and email addresses, phone numbers, and transit information, like flight numbers. So this is really, really cool.
Let's show how this works in example. So we have this string, right? We have obviously an address in there and a phone number, and we have this error. We're going to pass it in when we initialize Data Detector. And you see that when we have initialized this, we're passing in the different types of information to look for.
When you're creating this in your application, you only want to pass in the types that you're interested in because each additional type will incur a little bit more processing. So in this case, we're only looking for-- well, I guess that should be address and phone number. And then of course, because it's an NSRegularExpression sub-class, it's using that familiar enumerateMatchesInString method with options, range, and then enumerating each time with a block. In this case, we're just locking up the match.
All right, and finally, we're going to talk about CStringTransform which might be my favorite thing in the whole of Cocoa and Cocoa Touch. It's obscure, it's powerful. It's like perfect, all right? We have great string APIs and it's a shame if you don't know about them. So CStringTransform, it's a multitasker. It will strip accents and diacritics. It will name Unicode characters. It will encode XML hex entities which is useful if you're ever, you know, making XML or decoding XML. And you can also transliterate between writing systems which is kind of mind-blowing whenever you see it in action.
So here it is, meet CStringTransform. Of course, it's a C-Function, CF coming from Core Foundation. It's returning a Boolean whether or not it was successful. The first argument is a CFMutableStringRef which you remember that NSMutableString is toll-free bridge. So this makes it really convenient to work with. The range that you're going to put the transformation on is Next.
And if you're just doing it on the entire string, which you normally are, you just pass a Null. The kind of transform is the third argument. We're going to get into a couple of the constants you might pass in there. And then some of those transformations can be reversed. And if they are, you put a Yes there.
So if you were in English, English doesn't get all these cool characters which is really a darn shame. But as a result of that, of course, even the bigger shame is that most applica-- or a lot of applications can't handle this kind of input. We need to normalize that into something, you know, the base ASCII set.
So, you know, if we're going to turn that into that, you know, something that is more processible, we can use CStringTransform. So we do CStringTransform but passing in the kCFStringTransform StripCombiningMarks transform. It's a mouthful, but here StripCombiningMarks is doing both accents and diacritics. The difference between the two is sort of academic.
In this case, it just noted all the squiggly bits and interesting cool stuff is being removed. Next, naming Unicodes. Every character you see on a screen corresponds to some standard character documented in Unicode. Each one of those has a name. Some of those names are known like Latin capital letter A, or you know, ornamented A with the ring above, or symbols Snowman.
But what about this, Emoji, right? We love Emoji but what the heck is that called, right? But now with CFStringTransform, we can find out. So let's put in the code. Of course, because Xcode supports Emoji, you can put that right into your code, take the mutable copy of this pig thing and then pass in the kCFStringTransformToUnicodeName. If anybody didn't learn anything yet, you're going to learn something now. The name of that? Pig Face.
[ Laughter & Applause ]
All right. So finally, we're going to talk about, again, really, really cool stuff. Translating between writing system or Orthographies. If you don't [inaudible] there's really no way that you can begin to understand how that's pronounced. So it might be convenient to put into something that you do understand, a writing system that you do know.
CFStringTransform, as you might expect, does this pretty cool, well. You can pass in that Korean string we just saw and pass in the kCFStringTransformToLatin transform. And what that will do is it will transliterate from that Korean to a Latin representation. So that's how you say it. Actually, we're just saying "hello", "annyeong". But that works for a lot of the other languages too.
So you can transliterate between Russian and Greek and Korean and Hebrew and Chinese and Arabic and Thai, all sorts of these-- all these languages, you can put them into their Latin equivalent. So it's sort of a super power in a lot of ways, right? You can now read any scripts in the entire world with CFStringTransform.
It can transliterate between hiragana and katakana, the two phonetic writing systems of Japanese. You can convert between the two which is really convenient, especially if you're leaning Japanese or want to make a Japanese learning app for instance, pretty cool idea. Or you could turn it into a Latin, you know, the Romanization of it.
So even if you knew about CFStringTransform, you probably didn't know about this techno way at the bottom. I know I didn't. I didn't read the-- you know, who reads all of the documentation from top to bottom? But this note, you can pass in any ICU transform ID as defined in the ICU User Guide. So all of the really, really cool linguistic APIs, they're using ICU, this open source library under the hood.
So using-- you know, tying into that, you can pass in any arbitrary transform ID into your third option. So that means it's not only do you get to convert those-- you know, transliterate all those cool languages that we showed before, but you would do some foreign languages that you probably have never seen in your life before.
Things like, you know, Georgian or Bengali or, you know, Armenian or up there, IPA, one of my favorites. So it's a really cool and powerful method and, you know, [inaudible] actually show how you might use this in action. Let's say you've taken Apple's advice and you've internationalized and localized your app to a bunch of different markets and now you have users all around the world.
You want to make sure that you are able to handle, you know, whatever they throw at you. So here is a rather extreme case where somebody is very-- you know, they're saying hello in a lot of different languages. Let's normalize that into a way that we might be able to like index later. So first of all, we're going to take that string.
To transform it into its Latin equivalent, of course, we're going to do the kCFStringTransformToLatin. Next, we're going to get rid of-- again, there were a couple of accents there because Latin characters don't encode all of the different-- it doesn't-- can code the entire phonetic inventory of all the different languages. So, we take away those with the kCFStringTransform StripCombiningMarks. Then we use CFString lowercase to just turn it all lowercase, really, normalize all that input.
Finally, to get all the words in that, to get rid of all the punctuation and white space, we're going to use our friend enumerateLinguisticTagsInRange which, again, really excellent API for linguistics. You're going to pass in your scheme, so we're looking for tokens, options. No options here, and we don't care about the orthography argument. And then in the block, we're just going to iterate through. For each match, we're going to make sure-- we're going to see if it's a word. And if it is a word, we're going to add it to that collection of words that we created.
Finally, the output of that, we have-- this is what we started out with and then finally we have here. So that's something that you can read. That's something you can linguistically process. It's just a powerful idea of how you can use this in your application. So those are some of my favorite things in Foundation and Core Foundation. And with that, I'll pass it back to Scott. Thanks. [applause]
All right, so I think the thing we've learned is there's suddenly going to be an explosion of math apps and translation apps, right? OK. So, we are moving our way up to the layers. We're going to get to the really-- what I think is the really cool stuff now, the UI Layer stuff and eye candy [phonetic]. So let's look at Core Animation. And real quickly, if you're not super familiar with Core Animation, I'm sure most of you have heard of it.
It's a framework data that is actually just, again, on both iOS and OS X, and it powers all the super cool animations, the really fluid look that defines the iPhone, defines OS X. It powers that by staying on top of OpenGL. So it's this really great, easy Objective-C API that taps all that power of OpenGL so you don't have to know all the low level C API for OpenGL, so that's great. And just a real quick primer on what the key classes are.
There's CALayer which is the thing that actually shows up on the screen and every UIView and in, more recent versions of OS X, every NSView has access to one of these layers. And a CAAnimation acts on that layer over time, so it's-- for example, to change the opacity or change the color, that sort of thing. All right, so we're good.
What you may not know is that there are some pretty cool CALayer subclasses. So CAGradientLayer will actually animate between different gradients. Here, I'm simulating a sunrise, but you can pass it either an array of colors or an array of colors plus stops. So, you can imagine, you can go pretty crazy here.
And you can actually [inaudible] things you want to animate between. So-- And it turns out, this is actually ridiculously easy. So here, I've actually created an instance of CAGradientLayer. I just chose some random geometry, but you can do anything, obviously. I have three separate colors and I'm basically taking three sets of colors-- or sorry, three colors, two sets of them and using a starting value and ending value. So, I'm just starting with 2, 3, 3, just sort of for the aesthetic feel.
And then I'm switching to 1, 2, 2. So I'm using those three colors together. I set the duration to four seconds, sunrise takes four seconds, auto reverses, and I've already [inaudible] longer repeatCount here which is effectively infinity. And then I just add that animation to the layer, and then I can just go ahead and take that layer and add it to any view that that has a layer already on it.
So you can do that both on iOS and OS X. And again, this is what it looks like. So, it's pretty cool. So another sister, I guess, class of CAGradientLayer is CAShapeLayer and this is actually super cool. This is you are literally giving it two separate CGPaths and it animates between them.
It's not-- it's crazy. And you can also animate between multiple paths. Here, I'm just using two and it's actually a much more fluid than it appears here on the screen. But again, this is really, really simple. I literally just make a CALayer-- I'm sorry, CAShapeLayer and I set up my path and I can put all the vertices here 'cause that would become a crazy. But I'd have a starting path, an ending path. I create the animation for the path. And then, again, I just hit the duration, the auto reverse, repeatCount and I add it to layer. And it looks like that, so it's pretty cool.
Now, what would be really cool? How about if we took both gradient and shape and put them in the same example, what would that look like? I don't even know. Oh, it will look like this. So, you've got this crazy-- so what's actually happening here is the shape layer is masking the gradient layer.
So, you have all the animation that's happening on the gradient but the star, the shape of the star is actually clipping the bounds of the gradient, so that's awesome. And literally, all you need to do to make this work is you set all the shape layer code that I showed you before, you set that shape layer as the mask on the gradient.
So here's something else that you probably find yourself doing. You may have some sort of animation that responds to user interaction and sort of the first place a lot people go with this is that they actually update the animation as the user is dragging. But it's actually really computationally expensive to do it that way.
So instead what you can do is actually change the time offset of the layer itself and that the subtle thing here is that there's this protocol that you might not be familiar with called CAMediaTiming and the animations adhere to it but the layer is also adhere to it which opens up a whole range of option. So, in this example, for the example you just saw on the screen, I got two views, I've got the container and then the square, and then the slider to move and back and forth.
And I initially set the speed of the layer to zero. And, you know, a lot of these details I think you're probably familiar with, so I'm not going to spend too much time on them. But I have a BezierPath which is just a circle. And-- So the calculation or the pace sets the speeds to a quarter of a second and then add that animation to the square, the layer. And then I have this slider as I'm moving back and forth. I change the time offset of the layer and that's totally responsive, really super efficient, so that's the way to do that. All right, let's keep moving. Oh yeah, here's [inaudible] again in case you forgot.
So, here you go. OK, let's move on. So, we're going to look at Core Data. So Core Data, of course, is the framework that's available for both iOS and OS X developers as a way to persist your data between launches. And here's just a really quick overview for those of you that aren't familiar with the main classes.
Your Data Stored and Persistent Store, you access it through a Persistent Store Coordinator and then you fetch objects into this ManagedObjectContext. And those ManagedObjects then kind of like living your app and populate views, that sort of thing. So there's ManagedObject, ManagedObjectContext, and Fetch request. Fetch request is the thing that's pulling those things from the database.
But the thing that people kind of struggle in and actually in this week in the lab, [inaudible] a lot is people don't quite know how to do backgrounding operations and it turns out it's really, really easy. There's new API added as far back as iOS 5 in Lion that's been available, but not everybody has taken advantage of. So I just want to mention, when you create a ManagedObjectContext, you can specify that you want the PrivateQueueConcurrencyType and this is awesome because basically what it means is you get backgrounding almost for free. So what happens is you create this context with the NSPrivateQueueConcurrencyType.
You say performBlock with just any work you want to do and you don't even have to create the queue that does the work on it. You don't have to create the thread. You just say, "Go do this, I don't care what happens. Let me know when you're done and we'll move on." So it's super, super easy.
Here's an example. I mean it's almost [inaudible] to set it up. And then with concurrency type, PrivateQueueConcurrencyType, I do some work and I save, it feels great. And a few other quick hits Core Data here. When you're fetching, again in the labs this week, a lot of saw that people didn't know about a lot of this propertiesToFetch.
If you're fetching stuff from Core Data and you want to be fast, just fetch the stuff you need. So just say propertiesToFetch on name and phone number. You can get back just a dictionary. If you don't need the whole object, you can get back just the objects ID and sometimes maybe just want the account.
You can also do fetchBatchSize which is awesome. So if you have like people came in the labs and they're like, "Well, we've-- I have four million records." It's like, "Well, no wonder, your app is slow. You're launching, you know, four million records on launch." So just set Batch Size and then as you'll initially fetch a hundred and then as you kind of run through that array, it will go and fetch more.
And also if you're doing cross relationship fetching, you actually want to say, "Hey, during this batch, I'm actually going to need the artist. I'm going to meet the catalog. Go ahead and fetch that for me." And there was a really fantastic talk yesterday in Nob Hill. I definitely recommend checking the video if you're using Core Data. Even if you think you're doing the right thing, trust me, there are some pretty amazing stuff in there.
And one last thing, I don't know how many of you are actually familiar with this, but they're built-in store types in Core Data and most people you SQLite, but if you actually have a different data format that you need but you want all the really nice conveniences a Core Data, there's a class for NSIncrementalStore which you can subclass and actually implement your own storage type.
So, that's there, OK. So, we have a couple of iOS specific and AppKit specific tips. But first, who here has learned something already? OK. Wow, all right. Has anyone not learned something? OK, yeah, because I was going to call you on the pig face one. Pretty sure, I didn't know that, so-- OK. So I guess then a few bonus tips since apparently you've covered everybody.
UIKit, so this is-- this is one of these things where I think most people know about it but because it just came out in iOS 6, I think maybe not everybody is really using it. So UICollectionView is really, really awesome class that was added in iOS 6 that allows you to do pretty incredibly complex layouts. And out-of-the box, you just-- it's basically like a grid view for free.
So it's like a home screen for free just by creating one of these things. And we actually use it in the WWDC App that you see here. So this whole grid view is actually build with UICollectionView and we use a custom layout and the custom layouts are actually really straightforward to do.
So something-- you know, a lot of times when people run across a new class, they've got existing code and they're thinking, "But-- yeah, but I don't want the API. I'm going to have to sit there and figure out. And then I've got like not working what I'm already working on." But here's the great news about UICollectionView, the API is incredibly similar to UITableView. So you-- these are really just the methods you need, numberOfSections InCollectionView, and I'm just returning my-- the count, and numberOfItemsInSection, so it's just like TableView.
And then I can just return the view I want. So I'm saying, OK-- and this is actually [inaudible] code from the WWDC App that I've cleaned up a little bit, but this is actually what we're doing. So we pull sessions from a section. We get that particular session object.
We dequeue the cell just like you would do in TableView. And then we set the session and return self, that's it, and it shows up in the screen. The real work that's done in the app is the custom layout. And it's a little bit more in-depth, but you can do it.
And of course, with Mavericks, you know, being announced this week, we think we're going to get-- you know, a lot of people are kind of like, "Hey, you know, this iOS thing is really cool but I can actually be making Mac apps too and be really awesome." So one thing to know is if in the past you're used to working with UITableView and then you were thinking, "Well, I'd like [inaudible] Mac app but I don't really know what that's like," one thing you should know is that in Lion we added this version of NSTableView that actually use views just like UITableView.
So all that stuff that-- all those mechanisms that you're familiar with from UITableView, just doing arbitrary layout in interface builder and just returning entire views, it's actually-- you know, it's X now, so you can do it. And the same people that worked on UITableView or NSTableView, so you can imagine that it works pretty much the same.
And so, you get all that hardware accelerated stuff. You get the animation. Here are some of the animations facts you can do. And you can actually add Core Animation stuff. So if you for some reason wanted a TableView of shapes, clipping, gradients, or something like that, you could actually do that. And again, actually this is incredibly similar to the CollectionView example, numberOfRowsInTableView. You turn a row for the view and I just can change whatever properties I want before it gets displayed.
And the one thing I want to point out here, just calling out a little bit separately, is there's an existing class that's NSTableCellView which you can use generically. You can just use as it is or you can subclass it, or you can just whatever view you want. So if you have-- I have an MS-- MyGridView and I've just completely implement that from scratch. So it's just something I was using elsewhere but I'm including the table. So if you have a lot of flexibility there. All right. So, was that-- that was pretty fast, but I think we hit everybody.
So we got-- pretty much everybody learned something. So with all this stuff, if you have questions on any of this stuff, you can talk to our good friend Dave DeLong. He's the App Frameworks and Developer Tools of Evangelist. There's documentation and forms, in case somehow you haven't heard of those yet. And do checkout those other sessions 'cause they're really, really good. There's Designing Code for Performance on video and Core Data Performance Optimization for Debugging, and that is it. Thank you very much. [Applause]
[ Silence ]