Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2008-348
$eventId
ID of event: wwdc2008
$eventContentId
ID of session without event part: 348
$eventShortId
Shortened ID of event: wwdc08
$year
Year of session: 2008
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2008] [Session 348] Cocoa Funda...

WWDC08 • Session 348

Cocoa Fundamentals

Essentials • 1:03:45

Get an introduction to Apple's advanced application-development framework, Cocoa, and its primary language, Objective-C. Learn how to take advantage of common Cocoa programming paradigms, such as target/action, delegation and bindings. Through code examples and demos, see how Cocoa can help you easily create powerful, professional Mac OS X applications. iPhone developers will also gain valuable insights into the heritage of Cocoa Touch and learn helpful techniques for iPhone application development.

Speaker: Peter Ammon

Unlisted on Apple Developer site

Downloads from Apple

SD Video (775.6 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

  • Okay, welcome to Cocoa Fundamentals. This is session 348. My name is Peter Ammon. I'm an engineer on the Cocoa Frameworks team. Today we're going to answer some of the fundamental questions about Cocoa. Right, like, what is Cocoa? And why should I use Cocoa? And how can I use Cocoa? And how do I write a program that makes the groovy sort of Eye of Sauron type images during the 75-minute demo portion of a Cocoa presentation? So this app is called Squiggles, and it's a very simple app, but it'll have a lot of sort of nice Mac-like features, right? It'll support multiple documents. You can save a document and reopen it so you can work on it later.

It will have support for lots, you know, multiple levels of undo and redo. It'll have a nice, resizable window and a lot more. And what's great about Cocoa is these features are really easy. And sometimes they're automatic. You get them for free. And a corollary of this is, if it seems too hard, you may be doing it wrong. Right? If, if, uh, excuse me.

This slide went away. Right. When something seems more difficult than it needs to be, we refer to that as fighting the framework. And when you're fighting the framework, that's a good indication that you need to take a step back and think about the way you're designing your application.

So, what is Cocoa? Well, Cocoa is an object-oriented application framework. What's a framework? Well, a framework is something very literal in Mac OS X, right? There is a Cocoa.framework in the system library frameworks directory. And this contains, you know, compiled executable code and headers and resources and other things used by Cocoa.

More generally, a framework is like a library. For example, OpenGL. And you use a library by calling its code. So how do you use OpenGL? You call OpenGL functions. You can think of OpenGL as sort of being embedded in your application. But Cocoa calls your code. So you could think of your application as being embedded in Cocoa.

And the overall structure of your application is determined by Cocoa. For example, Cocoa tells your windows when they need to draw. It tells your application when it receives an event. It tells you when you're ready to quit, and things like that. As a result of this, most Cocoa applications have a very similar structure.

So, why should you use Cocoa? Well, Cocoa is a very mature framework, right? It's been around for one form or another for nearly 20 years, and it's driven by developer needs. So when developers are writing applications, they discover they need, you know, some functionality a lot. If it's something that many applications need, then that's something we consider adding to Cocoa.

And it's optimized for Mac OS X. So when you draw an image, it uses the most efficient path for drawing images on Mac OS X. If you draw text, if you, you know, manipulate files, it's going to do the right thing on Mac OS X specifically. It's very consistent, too. By this, I mean all the APIs work very similarly. There are very strong Cocoa conventions that the Cocoa frameworks follow very closely.

And it's full-featured and complete. It's not just a framework for drawing, you know, widgets and controls. It also supports localization and accessibility and printing and scripting. In fact, it supports these because Mac OS X applications need these features, and the applications we ship with the system all use these features. So Cocoa is our dog food, right? Let's look at some of the classes we have in Cocoa. And there's a bunch.

So here's some of the functionality. And there's so much there, it's hard to get our hands on it sometimes. So we like to organize it into what we call App Kit and Foundation. And App Kit supports some of the more-- oh, and this, of course, this list is not exhaustive. There's plenty more here.

And AppKit supports controls and windows and some of the graphical classes and functionality that you'd expect. And much of the consistency of the Mac OS X user interface is due to the use of Cocoa. If Mac OS X applications seem to look and work the same way, a lot of that is due to Cocoa providing the functionality for them. And Foundation provides more system-level functionality, like working with files and collections and XML. And it's possible to write, for example, a command line application that would use Foundation and not use AppKit.

So, let's move to a demo. Let's make our very first Cocoa application. Here's the first iteration of Squiggles. This is just what you get when you say Xcode new application. And we'll build and run it. We have a window, right? The window can be resized, it can be minimized. We have the color panel here. There's an about box. The application can be quit. So, let's go back to slides. So there was a lot there.

There's all this functionality, but there was only one line of code, and that's this NSApplicationMain. So, that's great, we get all this for free, right? But the next question is, you know, where does my code go? And I think this is one of the most common questions asked by developers new to Cocoa. They're not sure where to put their own code.

And I think developers who ask this are coming from a sort of a code generation perspective, right? A number of other frameworks like to-- they make their form painters or tools just generate code for them. And you can view that code and you can edit it. But Cocoa does not use code generators.

Instead, you want to think about your application from a more object-oriented perspective, right? So you think about the different classes in your applications and the instances of those classes and their relationships to one another. And then you start by setting these up in Interface Builder. So Interface Builder, if you're not sure, is a tool that operates on what are called nib files. And a nib file is just a serialized object graph. So it contains windows and views that have been serialized to a binary format and stored on disk. It also contains your own objects and relationships between the objects.

Most Cocoa applications have one nib at least. This will typically contain the main menu and perhaps other windows. And most Cocoa applications also have multiple nibs, often as many as one nib per window. And you can load a single Nib file multiple times. So here we have mail, three mail windows, and the way we've achieved this is by loading the Nib containing the window three times.

So let's think about the relationships and the objects in Squiggles. We'll use a model view controller design. I'm sure you've heard of that. This is a design which is very common in Cocoa applications. In fact, many Cocoa controls depend on model view controller. For example, the table view is just a view and it depends on having a model object to supply it with data.

So we'll have our model object, which we're calling a squiggle, and a squiggle will have a path, which is just the region the user drew in, and it will have a color and a thickness, right? And it will support one method, which is add point, and that will-- if the user clicks or drags to a point on the screen, that will be the point we add to the squiggle.

And we have our View object, too. And the View's responsibility is to draw the squiggle and also to receive events, mouse-down events in particular. We have a controller object which will manage an array of squiggles. So, with a bit of abusive notation, the model is really the array here.

And it will also trigger redisplays. For example, when a squiggle is added, it will tell the view it needs to redraw. So, what kind of relationships then do we have? Well, the controller, as I mentioned, will manage the array of squiggles, while the view and the controller will each relate to one another. So, the controller will tell the view it needs to redisplay, and the view will tell the controller when it receives an event. So, let's go ahead and set these up in Interface Builder.

Close this. So this is the same application. Going to open up Interface Builder here. Oops. We'll hide everything else. So here's our main menu, and here's our window. So now we've begun to answer the question, where did all that functionality come from? A lot of it is just right here in the nib. We'll start by adding a custom view, which will be our squiggle view. We'll put it in the window.

Then we will make it an instance of squiggle view, right? And we'll also have our controller object, which will be just subclassing NSObject. And I'll make this an instance of controller. The model will do code. So the controller has a relationship to the squiggle view. So we'll call it view, and this will be of type squiggle view.

Set this up now. There it goes. View. Likewise, the view will have Controller as its relationship, type Controller. We'll set these up. We have Controller. What we can do now is have it make these files for us and we'll set up the relationships. We'll add it to our project.

And likewise for the controller. Center file, write class files, controller. We'll add it. Going back to Xcode, you can see it's added our squiggle view and our controller. It's got the controller as an instance variable and the controller relates to its view. We need to set up the superclasses and such. So the superclass of controller is NSObject. The superclass of view is NSView.

Okay, so we could build and run this and it wouldn't look any different than what we had before, right, because we haven't actually told the view to draw anything. But we set up the basic relationships and classes in our application. Go back to slides, please. So I wish I could tell you that you can write an entire Cocoa application with just Interface Builder, but that would be a lie.

Eventually, you're going to have to write some code. Just like Java has the Java programming language and C# has it--excuse me, .NET has its C# language, Cocoa has Objective-C. That's the flagship language for writing Cocoa applications. And most applications on this system are Objective-C Cocoa applications, Safari, Mail, Keynote.

And if you're a little intimidated by Objective-C, don't be. Objective-C is a small programming language and it's an easy language to learn. So how does it compare to a language like Java or C#? Well, the good news is it's very similar in a lot of ways, right? These are all object-oriented language. They all have a single inheritance hierarchy, and they all support garbage collection, although in Objective-C, it's optional. But there's some important differences too. The first difference which people notice is the syntax.

In Objective-C, when you're calling a method, you do not use commas to separate arguments, and you do not use dot paren to name the method. So let's take a look at this in action. So for example, here's an Objective-C method invocation. Cell, draw with frame, in view. So the cell here is titled--is called the receiver. This is the object that the method is being called on.

Next we have the name of the method: drawWithFrame:inView: The colons are part of the method name. If the colons were not there, it would be a different method. You'll notice that the method name is broken up over multiple parts of the actual invocation. The parameters here are also interspersed with the method name. So here the parameters are content-rect and title-view. And in Java, this would be cell.drawWithFrameAndView, then parentheses each of the parameters separated by commas. So the syntax is a little different, but everything you're familiar with is already there.

Why do we have this crazy syntax? Well, one good reason is it helps to disambiguate parameters. So if you said in Java you say array.set, for example, on an array list, and you have foo and bar, it's not really clear which is the index into the array and which one's the object you're trying to store. But in Objective-C, replace object and index foo with object bar, it's clear that foo is the index and bar is the new object. And you'll find that we often, most methods in Objective-C are fairly verbose like this. This helps to improve the readability.

Another advantage is that it helps you write longer methods. Now, this isn't always a good idea, but if you decide to do this, it's easier in Objective-C than it would be in Java. Imagine this method in Java, you would have 100 and 300 and all these numbers just in a big list, and you wouldn't know what number means what. In Objective-C, it's clear that, for example, 100 is the number of pixels high for the new image.

So how do you declare a method? Well, here we have a method declaration, drawWithFrame, in view again. The first thing you'll see is the return type. This is in parenthesis. This is just the ordinary C cast syntax. So if you know C, you know how to type cast. That's how you declare the return type for the method.

Next we have the method name. Again, it's broken up into separate portions, and again, the colons are part of the method name. We have the parameter type. So here we take two parameters, NSRect and NSView, and the variable names. The formal parameters are frame and view. So in Java, this would be void, draw with frame and view, parenthesis, parameter type, parameter name, comma, etc. One last part that's important is that leading minus sign. This just indicates it's an instance method. You would call it a non-static method in Java. If it were a plus, it would be a static method like you know in Java.

How does Objective-C relate to C? Well, very well, it turns out. The good news is Objective-C is a superset of C, and all C code just works. You don't have to mess with, you know, P invoke or JNI. Even in C++, most C code will work, but you might have to typecast some mallocs or things like that. In Objective-C, it just works. It's a true superset. And in fact, Cocoa uses-- depends heavily on C. So if you know C, you're most of the way there towards being able to write an Objective-C.

It's also fully compatible with C, not just source code like we mentioned, but compiled libraries too. So if you want to use OpenGL, you'd use OpenGL from an Objective-C program exactly the same way as you'd use it from a C program. And it's also compatible with C++. Just like Objective-C is a superset of C, you can take those same extensions and apply them to C++.

Then you have a language called Objective-C++, and they have two disjoint object models. So you can't, for example, have an Objective-C object inherit from a C++ object. But there's some interoperability. For example, you can have a C++ object embedded in an Objective-C class as a variable. Then when you instantiate the Objective-C class, it will call the constructor for your C++ object.

And when your Objective-C object goes away, the destructor will be called for you automatically, too. And I know that a lot of you have, maybe you like to use Boost or you have a lot of C++ code you have for your cross-platform application, and Objective-C++ is a great way to take advantage of that while also using Cocoa.

So you'll notice that the NSView has an asterisk next to it, and this means it's an Objective-C object, but just like it means in C, it means it's also a pointer. In fact, all Objective-C objects are pointers, and this is, of course, true in a language like Java as well, except it's explicit in Objective-C, and it's hidden in Java. And there's no stack allocation in Objective-C like you can do in C++, for example. In fact, if you try to allocate on the stack, you get an error message. We have statically allocated instance of Objective-C class NSView. We forgot the asterisk.

but there's no asterisk next to NSRect. This is not a pointer. So how does this work? Well, it's just an ordinary C struct. Cocoa uses some C structs for efficiency, right, because using a struct can be more efficient than using an object. You can allocate it on the stack and such.

And there's only a few you're likely to encounter, so you'll get familiar with them very quickly. There's NSPoint, which represents a two-dimensional point in floating point coordinates. NSSize is a two-dimensional size. NSRect combines a point to NSSize. And NSRange is an integer range of a list or an array.

Lastly, the last important difference is dynamic binding. What is this about? Well, in a language like Java, methods are resolved at compile time. So if you call the name method on an object, the compiler has to know that this name method exists. And all it can do is call the name method. So if we--if object does not have--it's not of a type that supports the name method, you're going to get an error like this at compile time. You cannot find symbol.

But in Objective-C, methods are resolved at runtime. So if you call the name method on an object, if the name method exists, it will call it just like it does in Java. But if the name method does not exist, then some more interesting things can happen. The object can actually store that method invocation and play it back later. It can pass it on to another object. It can pick it apart and run some other crazy code to interpret it in some way.

So the lesson here is that objects can handle arbitrary methods, even if they aren't defined at compile time. And we refer to this, therefore, as sending a message. So here we're sending the name message to this object, and if the object responds to name, it will call the name method.

We'll see a use case for this sort of dynamic feature a bit later on in the session. Now, I know a lot of you are familiar with dynamic languages like Python and think, "Oh, great, if I have to use this dynamic language, I'm not going to have static type checking." But you actually do. For example, here's a variable called array. We meant it to be an array, but we typed it as NSString by mistake. We're calling an array method on it, Object.Index.

The compiler's going to catch this. It's going to say, "Hey, NSString may not respond to this method. Are you sure you wanted to send this message to it?" If it's an error, you can fix it. And if it's not, you can, you know, we'll see how to shut it up later. So the code will still compile. This is just a warning.

Now, if you really wanted to invoke this method, which the compiler is not convinced actually exists, you can do it. For example, here's the last object method on NSArray. And as you can see, it returns this type, id. What is id? Well, id is an object of any type.

And this allows you to avoid the typecasting. So I know in Java, if you want to take an object out of an array-- or excuse me, out of an array list, in the battle days before generics, you'd have to do the typecast of the type you want. In Objective-C, that's not necessary because of this id type. For example, if we call the last object method on an array, we can call string methods on this object, such as character at index. And the compiler is just going to trust us that this object in the array is really an instance of NSString.

Well, that's Objective-C, but there's also other languages you can use with Cocoa. Leopard ships with three of them. There's Python, Ruby, and AppleScript. And these are great options. Because they have really good interoperability with Objective-C, you can have a Python object which subclasses an Objective-C object. You can go the other way, too. And you can use any Objective-C code and libraries from within Python.

And the user can't tell the difference. These are launched by double-clicking in the finder. They are bundled applications. They work just like any other Mac application. So these are completely reasonable ways to write applications for Mac OS X that use Cocoa. Let's go back to our demo and look at how we do some custom drawing.

So here we're back in Xcode. We've got our squiggle. We're going to define this addPoint method we talked about before. So when the user clicks on the view, it's going to add a point to the current squiggle. What does add point do? Well, if there's not a path already, remember the path variable, we'll create a path and start us off at that location. There already is a path. We will just add a line to that point.

Our controller, what we're going to do is just for testing purposes, define a squiggle and give it a certain number of points that will form a square. So we'll make our array, we'll make it instance of squiggle. - We'll set it to an orange color. We'll set its thickness to something reasonable.

And we'll add a bunch of points, and these points will describe a square. Once we've done that, we'll add it to our array. We're done with the squiggle. This is our return self. Likewise, we have a squiggles property that the view will call in us so it can draw these squiggles. Save that.

And in our view, We're just going to define a gradient, and the gradient will just give us a nice background for our view. Here we'll draw the gradient, and then for every squiggle, we'll get its path out. We'll set it to a given line width, the width of the squiggle. We'll set it to the color of the squiggle. And then we'll stroke, so we'll draw a line around the squiggle, and we're done.

So when we run this, what we expect to see is a view with a gradient background, which we see, and an orange square, which is the one squiggle. Okay, this isn't very exciting yet, but we'll get there. Let's go back to slides. So, what did we just do? Well, first we have to talk about the class hierarchy of Cocoa, right? Cocoa has, for most use cases, a single root class, which is NSObject. And NSObject provides facilities like allocation and deallocation, reflection, some logging, and reference counting for memory management.

So here's part of the class hierarchy of Cocoa, a very small part. NSObject is at the root. It's got NSView and NSWindow inherit ultimately from NSObject. Because they both sort of respond to events, they have an NSResponder intermediary. And there's other classes, NSArray, which is an array of objects, NSLock, which is used for synchronization.

And there's also some C structs, as we saw, which don't participate in the class hierarchy because they're structs, they're not objects. So, NS size, NS point, and NS range. So we saw NSView, and NSView was doing the drawing. So a view is a rectangular portion of the window, and it's not itself a window.

I know in Windows, for example, a region of a window is also itself a window. In Cocoa, they are unrelated. And the view will draw within the region of the window it describes, which refers to its bounds, and it can also respond to events in that same region. And it can contain other views. So here is a picture of one of the preference panes.

This is the screensaver preference pane. And there's a bunch of views within this window, as you can see, the rectangular regions. So the OpenGL view is drawing the OpenGL portion, and there's a table drawing-- showing you all the different screensavers you have available. And, of course, each of these views is embedded in a larger view. Here we have the tab view, which contains multiple tabs. Each tab has views inside it. And the root-most public view is called the content view, and you can get the content view for a window by just asking it, sending it the content view message.

Most widgets, controls in AppKit are subclasses of NSView. So TableView and OpenGLView and TextView, all subclass NSView. But don't think that every subclass also has view in its name. So ColorWell and PopupButton are all subclasses of NSView, but they do not have view in their name. And it's very common to subclass NSView. Most Cocoa applications will do it.

And the reason you subclass NSView is so you can override some of its methods. For example, drawRect is one we overrode, which will be called when the view is told to draw by Cocoa. MouseDown is called when the user clicks in your view, of course, and KeyDown is called when the user types a character. And you get things done with the view by overriding these methods. And Cocoa will call them for you at the right time.

So for example, with DrawRect, all we had to do was implement DrawRect, and Cocoa will automatically call it when the view needs to redraw. For example, when the window is resized so our view changes its dimensions, or when our view gets moved within the window so it might appear different.

And you can also trigger your own redisplays with the setNeedsDisplay method by sending that to the view. The draw rect has a single parameter which we're not using here, which contains the actual region needing redraw, so you can optimize your drawing to only draw the portion that actually needs to be drawn.

On to memory management, and there's two different ways to manage memory in Cocoa. There's reference counting and there's garbage collection. And reference counting is an older method, which is available in every version of Mac OS X and also the iPhone. Garbage collection is new in Leopard and is not available on the iPhone.

The way you choose is very easy. In Xcode, you just pick from pop-up whether you want the first option here, which is reference counting, where it says unsupported, or garbage collection, which is the last option. And the middle option is sort of a mode. It supports both methods, which is useful for frameworks like AppKit. But if you're writing an application, it's only the first or the last options you want to use.

So how does reference counting work? Well, a theory behind reference counting is that object lifetime is a global problem, right? How does an object know when everyone is done with it? And the hope for reference counting is to make it into a local problem, where every object that uses another object just indicates when it's using it and when it's done with it. When everyone is done using that object, it knows it can deallocate itself and free up the memory.

And a lot of you have maybe experience with reference counting and you think, you know, I'll have to constantly be adding and removing references. And the good news is you will not have to do this. Due to a feature called NRS Auto Release Pool, which we'll talk about, it's fairly uncommon to have to add or remove a reference count.

Another objection is, "I'll never know what it's actually doing. It'll constantly be doing this behind my back." The good news is it won't do that either. This is not like AutoPointer from C++, where there's all these implicit changes. Everything is very explicit. So if you understand the rules, which are very simple, and you follow the rules, it will work consistently and well for you.

What are these rules? Well, every object has a reference count, right? An object starts with a reference count of one. So here we have an instance of box called myBox, and we've knitted it, so we have a reference count of one. Now, if we send it a retain message, it will then up its reference count to two. If we send it a release message, of course, the reference count will go back to one.

If you have an object with a reference count of one and you send it the release message, well, it's not going to go down to zero. Instead, it will free itself. It will call dealloc on itself. So, dialog is always called for you by NSObject. It is never something you want to call yourself.

The third piece here is what's called auto-release. What auto-release does is it will send a release message later. What does later mean? Well, if you send auto-release, it will not change the retain count now, so it's still going to stay at one. But what it will do is add a reference to your object to this sort of global pool, a per-thread pool, called the NS Auto-Release Pool. Then, when the auto-release pool is torn down, which happens automatically at the end of every event, although you can set them up yourself, each object in the pool will be sent a release message, and the pool itself will be destroyed.

So this is very handy because it allows you to return objects and also clean them up yourselves. Callers aren't burdened with the details of managing memory for these transient objects, which is most objects. So for example, if you call the uppercase string method on an NSString, you get back a string which is an uppercase, but the string you called it on is responsible for destroying that object. If you do not want to keep the object around, if you just want to draw it or log it or write it to a file, you do not have to retain or release it at all. You can just use it. It will be cleaned up for you.

So, in summary, when you pass an object to a method, you do not retain it or release it. The object that you're passing it to will retain or release it if it wants to. When you get an object back, you need to retain it if you want to keep the object around, which is uncommon, release it if you don't.

And if you just want to use the object and forget it, you do not have to send any memory management messages at all. The exception here are the allocation primitives. These return objects which are not auto-released, so alloc, copy, and new are the only three examples of these, or methods that have these, start with these words.

Okay, let's talk about garbage collection now. And garbage collection, like you might expect, means that objects are cleaned up for you automatically. This is only available in 10.5 in Leopard. And it's a modern and full-featured collector. So if you know something about garbage collection, the good news is it's very modern. It's generational, which means it doesn't have to scan your entire heap every time through. It wants to collect objects. It's exact.

So if you have an integer, which happens to reference an object, you know, that happens to have the same value as a pointer, that integer isn't going to keep that object around. It's not going to root it. It's concurrent, so it operates on a separate thread in the background. Your application isn't going to have to pause and wait while it collects the garbage.

It's multi-threaded, so it supports multi-threaded applications. And it supports finalization and weak references, which are the semantics you want from a modern garbage collector. So it's a very good collector. And under garbage collection, these reference counting methods, like retain and release, are not called like you'd expect. But another method which is not called is dialog.

This might be surprising. And instead of dialog, finalize is called. And finalize is a chance to do sort of last-minute cleanup, for example, closing file descriptors or sockets. And most classes do not need to implement finalize. In fact, you should try to avoid it because finalize can be a drag on your performance.

So you might expect, you know, Objective-C supports garbage collection, I don't have to worry about any memory management, but C and C++ code still uses the traditional memory management. So if you call malloc, and you wanna get a bunch of memory back from malloc, this memory you will still have to free. It was not freed automatically for you by the garbage collector.

And likewise, if you store an object into this memory, well that memory's not scanned, so it's not going to count as a reference to your object. Your object may still be collected. And this may seem like counter-intuitive, but this really is something you want, because it means that C libraries are not changed by garbage collection. This isn't gonna interfere with a library like OpenGL.

But if you do want to use garbage collection with these C-type functions, you can. There's a way to do this. There's a parallel set of functions. So there's NSAllocateCollectible, which allocates memory which is then reclaimed by the garbage collector when it's unreferenced. And if you store an object into memory that you allocated with nsallocate collectible, it will count as a root and your object will not be deallocated. All right, let's go back to the machine and do some event handling.

So we're going to start by adding two new methods, start new squiggle, which will be called when the user clicks on the view, and continue squiggle, which will be called when the user drags the mouse. is the founder of Cocoa Touch, and he's the founder of the Google Cloud Platform.

We'll add some helper functions here. So we'll start by saying current squiggle, which is whatever we're drawing right now, and that will be the last one in our array. We'll have methods addSquiggle, which will allow us to add a squiggle to the array and likewise remove squiggle. The two methods we just declared will have start new squiggle. We'll make a random color, so we'll just pick random floating point values for the color. We'll make an instance of this squiggle. Because we're calling alloc, we'll have to make sure to release this later.

We'll set it to the current color. We'll set the thickness to another random value between one and four. We'll add the point that the user clicked to the squiggle. We'll add the squiggle to ourselves. Then we'll tell the view it needs to redraw. And I see I forgot to actually release this. Likewise, Continuous Squiggle will get the current squiggle that we're drawing and add the point that the user dragged to that squiggle and tell the view to redraw.

The view needs to call these new add and continue methods. So we have in mouse down, which is called in the user clicks, we'll get the location the user clicked on and we'll call this start new squiggle method. Likewise, with mouse dragged, we'll get the point the user dragged to and we'll call continue squiggle with that point. So now we should have an application where you can do some basic drawing. So now if I click, I can draw with random colors, different designs. Okay, so it's getting more interesting now.

We saw this, the way we handled these mouse down and mouse dragged events was just by overriding methods on NSView. So we override, And the event that's passed to them is a single event type for every possible event, and it has methods like the type of the event.

Is it a mouse down? Is it a, you know, a key event? And when it happened and where in the window it happened, what the user typed and things like this. And the way you handle these events, as I said, is to override methods such as mouse down in your view.

Cocoa will call these methods for you at the right time. Let's go back to a demo now. So now what I want is to have the We want to draw this squiggle multiple times to get that sort of vortex effect. And to do that, we're going to define will be using a change rotation count method on our controller. This will be called when the user drags a slider. So here we're going to uncomment change rotation count.

Here we're going to define it. When the change rotation count is called, we're just going to get the value of the slider and store that and call setNeedsDisplay to tell the view to redraw. When the view uses this, it will be in draw rect. What it will do is-- I didn't comment this out-- it will make a rotation, an NS affine transform, and it will rotate by a certain number of degrees. And all that will do is, every time we use this, it will cause the content of the view to rotate a bit, and then we will redraw it.

For every value, every number rotation that we set in the slider, it will cause it to draw the squiggle multiple times. We'll see how to set up the slider now. Here's our window. We'll drag out some space for the slider. We've got a horizontal slider. We'll give it a size so it spans the view.

And we'll set as its action... this method we just defined, changeRotationCount. So now... When I draw this, I can have it-- oh, it didn't work. I forgot. It took a second? Oh, there it goes. Oh, I didn't make it continuous. So, as a... Oh, it doesn't matter. Okay, let's go back.

So what do we just do here? Well, let's say you have a button and you put it in a window. And that's really easy to do in Interface Builder, right? And the next question is, "Now what?" Where does my code go? This is just a variation of the question we asked at the very beginning. How do I make the button do something when it's clicked? Well, you might think, well, hey, NSButton subclasses NSView. I know how to handle mouse events.

I'll just subclass mouse down. And that would work, but that's a lot of subclasses, right? If you have to subclass NSButton every time you want to have it do something else when you click on it, you're going to wind up with dozens of subclasses. And besides, this is the wrong place for this code. NSButton has enough to worry about just showing the user interface. It doesn't need to have all your business logic in it. So Cocoa has better ways to separate what happens when you click on a button from the button itself.

Subclassing is not necessary for most classes. You have a subclass and its view, most of the time you don't have the subclass. We have three different methods for separating the logic from the actual, from the class. So we call these target/action, delegation and notifications. So target/action means that when you click a button, it needs to make something happen.

And the way it does that is by every control having what's called a target and an action. So the target is the object that will be receiving the method, the object where your code lives, and the action is just the name of the method that will be called when the user clicks on the button.

And you can set these up very easily in Interface Builder, as you saw. So, for example, our button could have a target of the NS application and an action of hide. Then, as you might expect, you click on the button, it makes your application hide. In our case, we have a slider and we have our controller, and the target of the slider is the controller and the action is this change rotation count method. What we did was we declared this method change rotation count. Oops. Gotta go through this again.

We declared change rotation count. This IB action thing might be a little confusing to you at first, but all this is is an annotation for Interface Builder and also for you. So when you get a Cocoa application you're not familiar with, you can look in the header files and it's really clear, "Hey, this method has IB action.

I know this is a method that's called from a control that the developer set up in Interface Builder." And these are not some sort of weird extension to Objective-C. All these are are defined. IB action is defined to be void, so all action messages return void. And IB outlet is something else. It uses set-up relationships that is compiled to nothing at all.

Now, every action message-- or method has one parameter, which is the sender of the action. In our case, it would be the NS slider. And this is useful because it allows you to have one object with one action message, action method, that can be hooked up to multiple controls. So we could have multiple sliders or buttons in different windows calling the same method. And we could figure out which one the user clicked on by looking at the sender.

So, just to summarize, you can define your methods, such as change rotation count in Xcode, and then you can hook these up into your controls in Interface Builder. So another approach we have for separating objects and factoring applications is called delegation. Delegation is when one object assigns responsibilities to a helper object. The helper object is called its delegate.

And the object with the delegate will call delegate methods on its delegate object. And maybe you know C# and you think, "I know what delegates are," but these are something totally different. In C#, a delegate is sort of like a function pointer. In Objective-C, a delegate is just an object which provides some functionality for another.

So every class that has a delegate has its own list of delegate methods. And you're--you use the delegate methods just by implementing them. You don't have to inform the class, you know, "Make sure to tell me when your--you know, if you're a window, when your window is going to close." And you can implement some of these or all of the methods or none at all. So for example, Windows should close, all you have to do is implement this and it will be called on your delegate at the right time. Cocoa knows to call it based on using introspection on your object.

In your window should close method, the window is passed to you. This is very similar to target/action, where the control is passed to your action message or your action method. Excuse me. Here the object is passed to the delegate method, and this allows you to disambiguate between perhaps multiple windows that all have the same delegate.

And it's very easy to set up a delegate in Interface Builder, just like it is in Xcode. Excuse me, just like it is with target/action. You can do it by calling setDelegate in Xcode, or you can hook it up by dragging an interface builder. Here we're having our object as the delegate of the window.

So once you've done that, once you've hooked it up, you have to implement your delegate method. For example, Windows should close. And here we're saying, you know, if our document has some unsaved changes, then we'll confirm unsaved changes. And if the user does not want to actually close the window, then we'll return no and the window won't close.

So this window will recognize, hey, this object implemented this delegate method and will call it. And then you're done. You don't have to do anything else. So delegation is a good thing. Why is it good? It helps you factor your application into separating your business logic right from your NS window.

The logic can live where it belongs. You don't have to make a bunch of subclasses just to change behavior. And it's really convenient. Often you already have an object which makes a perfect delegate for the window or for whatever has the delegate methods. And it's really easy to set up a delegate relationship.

So what kind of things can delegate methods do? Well, sometimes they can influence the object. So we saw windowShouldClose. That gets called to determine if the window should close, and if the delegate method returns no, the window won't close. But sometimes they're only purely informative. For example, menu has a delegate, which will tell you when the menu is about to open or close. Once in a while, some classes, like NS Toolbar, depend on their delegate for lots of functionality, for everything. They can't work with a better delegate.

The third style of separating the sort of concerns is called notification. And a notification is when an object just broadcasts events. For example, the window has a notification where it says, "I'm going to close." It says, "Window will close notification." And then normally the window will just go away.

If an object listens for these events, if it registers via NS Notification Center, here comes the object and it's listening. When the window says, "I'm going to close," the object will hear this and it can take action, jump up and down. And this is really useful compared to delegation because you can have multiple objects listening for one notification. So here we have three objects all listening for the window as it broadcasts its notification.

However, notifications can't be used to influence the object. So the window, the objects cannot veto closing from a notification the same way they can from a delegate. So to use a notification, you do it by registering with NSNotificationCenter and telling it which notifications you want to receive, and you receive a notification the same way you do with target action where you say this is the object I want to receive the notification on and this is the method you should call.

So, for example, for the window should close, we'll add observer self. This is the object that should receive notification. We want to have window closed called on us. That's the name of the method. The name of the notification is we'll close and the name of the object, the object itself is the window we want to be notified for.

But if you say "null" as the name, this is very useful because it will let you listen for all notifications for the window. So the window will close and the window will resize. The window will become key. Everything the window tells you it's going to do, you will receive. And likewise, you can listen for notifications from any object by passing "null" as the object of the notification. So this will tell you any time any window is going to close.

And the third mode, which is very rarely used, is to say null for both the name and the object. This will tell you every time any object posts any notification. This isn't usually very useful, but it's there if you need it for debugging, for example. And you can hook into the NS notifications yourself by just defining your notifications. And this is very easy. You just define a string, and that becomes the name of the notification.

And a nice property of notifications is they don't interfere with garbage collection. So, for example, in C#, it's common to have an object listening for an event, and then that object is never collected. It just gets leaked. So for example, say you have a button and it wants to listen for the NSControlTintDidChange notification.

So this is a custom subclass of button and it needs to draw differently depending on if the user selects Aqua or graphite in the appearance preference pane. And by listening for this notification, you can be told when the user changes this and you can change the way you draw. This will not prevent the object from being garbage collected, so the object can still be collected even though it's listening for this notification.

Under reference counting, though, you still must unregister with the Notification Center. Otherwise, the Notification Center will try to message your deallocated object and your application will crash. Under garbage collection, you do not have to deregister. So notifications are good because they loosen coupling between the objects, so the object can listen for a window will close notification from anywhere. The window doesn't have to be aware of that fact.

And it also provides a very generic interface to system events. So we saw the control tint did change, but there's also disks were mounted or unmounted or applications launched or quit. And this is all available through notifications. You do not have to learn some separate API for every different possible event like this.

Let's go back to demos. With this version of the app, I've changed the controller to be an instance of-- or a subclass of NSDocument. And that's mostly all I did. So what NS Document has us do is we have to define methods for reading and writing, and we'll see how we did that. Here we used serialization, although we didn't-- I'm not going to talk about serialization.

And by making that simple change, we can have multiple windows. So here I can draw and-- "We can also save these, so I'll call this Vortex for example. "And when I quit, I can double click here and my document is available for me to continue working on. And this took very little code to do.

Go back to slides. So, as you know, a lot of Mac OS X applications will view and edit files. For example, Xcode and Instruments and AppleScript and Keynote up here. And these are referred to as document-based applications because they use the NSDocument class. And the NSDocument class gives them very rich and uniform behavior. So all Cocoa NSDocument-based applications will work very similarly.

And it gives you a lot for free. So, for example, if you're working on a file and the user moves the file, the Cocoa Document class will notice that and give the user, you know,

[Transcript missing]

And it has a bunch more features, which just happen for free. All the save menu items work correctly for a Macintosh application. It's got auto-save for backing up the files, and it will preserve aliases and get a lot of difficult functionality correct.

So to use NSDocument, it's very easy. You subclass NSDocument to support your own file type. So for every file type you want your document to -- your program to support, you have a different subclass of NSDocument. Then you override a read method, which is called when your document needs to read from the file, and the write method when the document needs to write to the disk.

And then you override the window nib name to show your user interface. So this is just the name of the nib, which-- and its document should instantiate to show the window type for that document. And you can set these up very easily in Xcode. This may look like a lot of work you have to do, but you can do most of it in this window right here. The document-based template in Xcode gets you started.

So, I'm not sure about you, but often I'll get to the end of an application and I'll think, "I forgot about undo." And I'll try to tack on undo, but this can be hard to do, right? Undo is difficult to tack on at the end. You have to think about, "Oh, I need to have perhaps a command pattern and I have to find some way to make this undo stack." It seems like an easy feature, but it's often not.

But Cocoa gives you an undo class for free. It's called the NSUndoManager, and it will handle undo and redo to multiple levels. But it also does more than that. NSDocument will hook into undo, for example, to know if the document has unsaved changes. And every document has its own undo manager. You can get at it by calling the undoManager method of NSDocument. So, in our class, our application, we have this addSquiggle and removeSquiggle, and these methods are inverses of each other, right? Every method--each method will undo the other one.

So what we'd like to have happen is by maintaining an undo stack of methods that should be called when the user hits undo. So when we add a squiggle, what we'd like to have happen is remove squiggle needs to go in the undo stack. And similarly, as we add more squiggles, the stack will get higher with these remove messages. And then when we start removing them, the stack will start having these add squiggles inverse methods applied to it.

Well, NSUndoManager will manage this undo stack for you. And the way it does this is very interesting. It does it by you sending the undo manager the messages you want to receive later on. So, for example, our addSquiggle method We want to have removeSquiggle called on undo. We'll get the undo manager.

We'll say prepareWithInvocationTarget self. This means I want you to call the following method on me. And then you call the method you want to receive. Right? RemoveSquiggle is not an instance method of undo manager. It's an instance method of your class. So this is an example of dynamic binding of Cocoa and Objective-C in action.

And also, Redo is handled for free. So if in--in Add Squiggle, When that's undone, you get a remove squiggle method. And then when--within that remove squiggle, when you add to the undo stack, it will actually add to the redo stack for you. And as I said, it also integrates with NSDocument.

So Undo Manager is not just a way to handle undo and redo. It also lets NSDocument know if there's unsaved changes. That allows it to put the dirty spot in the close button. It allows it to warn you if you try to quit when there's unsaved changes. So if you've seen this dialogue before from TextEdit, for example, this dialogue appears because you tried to quit or close the window while there were unsaved changes. So let's see undo in action.

So here we have our application again. And in the document, all we're going to do is add these two lines. So in a remove squiggle, we will call add squiggle. In AddSquiggle, we'll tell the undo manager, "Prepare yourself with an invocation target of me," and then call RemoveSquiggle.

So Add will tell the undo manager to remove, and remove tells it to add. Now when we run this, as soon as I start drawing, you can see we get this dirty spot up here. Now I can choose Edit/Undo and it goes away. I can do multiple squiggles here. Let's make that kind of interesting.

[Transcript missing]

So, Undo Manager integrated with NS Document to support many of the Mac-like features, such as warning you when the application is quit. All right, so what do we see? Well, we saw Objective-C, the programming language, and some of its features. We saw nib files, which are a way to serialize an object graph to disk and how you set up your user interface in Cocoa. We learned about the Cocoa memory management techniques. And different ways to factor your application so you don't have to make a bunch of subclasses with delegation, notification, and target/action. We looked at some classes, NSObjects, NSView, and NSDocument, and we saw how to get work done with them.

But there's a lot more to Cocoa we haven't seen, right? We didn't talk about all the features of Objective-C. There's still properties, and there's still fast enumeration and categories. We didn't look at any of the collections that Cocoa has, so there's arrays and dictionaries and sets. We didn't talk about the key value observing or coding features of Cocoa, which are used for binding, for example. Binding allows you to have a control synchronized with your model without having to set up explicit target actions. We didn't talk about drag and drop or copy and paste.

And of course there's scripting and localization and accessibility, and these are all really important features of a well-polished application. And Cocoa's got the serialization, which we used for our document, and it has a remoting feature, which is useful for objects in remote processes or on different computers. And of course, the whole core data framework.

In closing, the takeaway is that Cocoa gives you the sort of functionality that Mac OS X users expect from a polished Macintosh application. And the frameworks are easy to learn because they consistently follow the Cocoa conventions. And it's not just AppKit and Foundation, but also frameworks like Core Image or QtKit or Core Data all follow the Cocoa conventions. So if you use -- if you understand the Cocoa conventions, it's very easy to learn these other frameworks. By using Cocoa, you can write amazing apps in very little time. I'm sure you will.

For more information, you can contact our Cocoa evangelist, Derek Horn, or for questions about the Xcode and interface builder, there's Michael Jurowitz, and of course, there's the documentation. And if you'd like to come talk to me or the other Cocoa engineers, there's a lab on Thursday from 12:00 to 1:45.