Video hosted by Apple at devstreaming-cdn.apple.com

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: wwdc2011-322
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 322
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 322] Objective-C...

WWDC11 • Session 322

Objective-C Advancements In-Depth

Developer Tools • iOS, OS X • 58:31

Join experts from the Objective-C runtime team as they dive deep into the latest runtime and language advancements. Discover how LLVM is helping to advance innovation in Objective-C, learn about new language constructs, and find out more about Automatic Reference Counting.

Speakers: Blaine Garst, Greg Parker

Unlisted on Apple Developer site

Downloads from Apple

HD Video (163.9 MB)

Transcript

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

Good morning. My name is Blaine Garst. Thank you for coming to the Objective-C Advancements In-Deepth talk. Today's talk is in two parts. In the first part, I'm going to be talking about Objective-C language extensions, extensions that work anytime, anywhere, and then a fair amount of detail on extensions that only apply under Arc.

And in the second half of the talk, given by Greg Parker, he'll talk about Arc internals, implementation details you may or may not need to be aware of that could well be very interesting anyway, some performance slides, and some other things. So everything we talk about today is available via the LLVM Compiler 3 found in Xcode 4.2.

So you have to be using that compiler to see all of these features. So let's just get started with the extensions that work everywhere. So the first one you've already seen a little bit. You've seen addAutoReleasePool. In the example code you see there, you've typed this again and again, maybe. I don't know, maybe some of you have never had to code up an AutoReleasePool, but if you have, due to some performance concerns, this is what you have to do.

Now, the thing about an AutoReleasePool is, even though it's an object, you alloc and init it, it's not really much of an object. You can't really, well, for example, have you ever tried to retain a pool? Have you ever tried to stick it as a global variable or an instance variable? It just doesn't really work as an object because really it fronts for a background service that sits and works on every thread's behalf to hold onto intermediate temporary objects.

And so the object part is just a thin veneer on top of that, and what we've done in the compiler is we've added syntax for it. We have an addAutoReleasePool construct that gives you exactly the scope for where you want that collection of temporary results to happen. Because of the fact that we're no longer pretending that it's an object, it's a lot faster, we've done lots of optimizations, and this is the construct that you should use everywhere all the time. Let's take a look at another feature. here.

Let's talk about instance variable declarations. Instance variables are, as you know, declared in the Add Interface section. Well, shoot, how often are your instance variables really part of your interface? Your interface is the methods you expose. You don't really expose public instance variables, so instance variables aren't really part of your interface, but we require you to declare them there, and that's not really very good information hiding. So I'm glad to say there's been some movement on this. So on iOS and on Mac OS X 64, 64-bit, we have some new opportunities for you. You can now declare instance variables in a class extension or or directly in your add implementation file.

Okay, I can tell. I don't need to say any more about this, but in fact I'm going to anyway. I'm going to give you an example. So let's say you have a wonderful class, an elegant class, and it hides all these messy details. That's what you want to write a class for, right? But you have to expose all those messy details in your header file.

So let's take one example. Let's say you've got a single file implementation of this. What you really want to do is take those messy details and just move them straight down into your add implementation section. You end up with a clean public header and the details where it's important, where you can actually use them.

Let's take the same case, the same messy public header file, but let's say you've got multiple implementation files that need that header. Well, that's where you use the class extension. You move your details into the class extension, leaving you with the same clean header. You put the class extension in a shared private header that is then imported and used by all of your implementation files, and you've solved it for that case as well.

Now, for those of you who aren't so familiar with a class extension, the syntax is very much like a category only without the category name. So I have a funny feeling that class extensions are going to get a lot more use nowadays. Let's go on for a, take a look at another feature.

So every great app starts with a great idea. So let's say you've got a great idea, and in this case, let's say you want to ship it on iOS 5. That's great. But you don't want to limit your app to iOS 5. You want it to deploy down to earlier releases as well, iOS 4, iOS 3. So that's fine. We know how to do this. You start with the iOS 5 SDK, and you just set the deployment target down to 3.1.

Okay, that's fine. Code along for a while. Then you come across a really neat new feature that's in iOS 5. You go, hey, I know where I can use that some of the time. How do I do that? In this case, I'm talking about a JSON serialization class, for example. And so the way we ask you to do it today is to look that class up at runtime dynamically by string name. Okay. So you put it into a variable that represents the class, and then you message the class.

And so this works. There can be some issues if you forget how to spell the new thing. There can be some issues if you forget how to spell the methods that you're supposed to use with it. And so I'm happy to tell you that there's another way to do this.

It's called weak linking for classes. And you just use the class more or less the way you would otherwise. You simply test to see whether it yields a non-nil result. Okay. Because on earlier releases where that class doesn't exist, that reference, that NS JSON serialization string yields a nil value.

Now, the other important advantage of this is that we don't have any mechanism prior to this that would allow you to subclass one of these new things. Now, JSON serialization is not really a class you're going to subclass, but there are plenty of classes that you might want to, and you now can do that using the weak linking facility. Okay. So it deploys down to iOS 3.1, and the most recent Mac was 10, 10.6.8.

There's a slight caveat. If the entire package doesn't exist on 3.1, then this doesn't work. So it's really for classes in new classes in packages that exist on earlier platforms. But this is a much better way to do it. You get static type checking, everything you want. Okay.

Let's go on to another one. Stronger type checking. How many people have declared a variable to be one type and then goofed up and initialized it with something else? I see hands. Well, I've done this, okay, and I have to find out about it at runtime quite often, right? Well, no longer.

So, compiler has been taught that the init method is the initializer for classes and that it returns an instance of the class that it's sent to. So, the compiler knows that it returns an instance of that type and that an instance of a mutable set is not appropriate to be assigned into a variable that's supposed to be holding a mutable array. And so, we get a nice compiler warning at this, from this. And so, you should always do that. Always look through your warnings because sometimes they can save your app from crashing.

Now with that, that's actually an interesting prelude because by teaching the compiler about the init method, that's a lot of what we're doing with Arc. So let's talk about Arc. So if you've gone to the preview talks, which I hope you have, you'll know that Automatic Reference Counting automates your retain, release, and auto-releases.

It works for Objective-C objects only, doesn't try to deal with malloc and freeze, and it doesn't work -- it doesn't automate your use of core foundation or core graphics or some of these non-NS object-based objects on our system. And of course, it interoperates with existing retain, release frameworks and code. So the question is, how does the compiler get it right all the time? And the answer is two things. We've taught the compiler about Cocoa conventions. And we've taught the compiler about ownership rules for variables. So let's talk about each of these in more detail.

COCA conventions. The language, the Objective-C language itself does not specify allocation, initialization, or destruction. Cocoa does this. We changed this 18 years ago. It used to be there was new and free, and we introduced ALEC and NIT and whatever, this Cocoa family of methods. And you all, you know, have been asked to learn these in order to program properly and carefully on Apple products. Well, after 18 years, it's time we put these into the language, don't you think? So that's what we've done with Arc. So let's talk about these in more detail. So methods beginning with ALEC and NIT, new and copy yield, what we call plus one retained items.

You have had to know to have a plan to get rid of that object or else it would leak. So this works great. The compiler makes this happen. So for example, if you have, say, a singleton or maybe an immutable value object, you know, the copy is just returned self. And so what Arc does is make sure that you return a plus one. You don't have to think about that anymore. Good. It works. It's fine. It's very neat.

But what about names that don't follow conventions? Hmm. Okay. Let's think about it. Let's say you've got some unconventional names. Let's say you've got a copyright notice and a copy left license, or you like to create objects with a make new thing primitive. Well, hmm. We're not really copying a right notice or copying a left license. You know, that's just -- you know, we humans can read this and understand it, but the compiler can't.

So, hmm, is this going to be an issue? Well, let's take a look at one of them. Let's say you've got a license implementation that returns a license, and you've got a client of that somewhere else, the copy left license client. If you compile both of these files under Arc, Compiler introduces a retain where you create one, and it introduces a release where you use it. Even though it may not be what you intended, it just works. So if everything you code up is compiled under Arc, it just works and you probably don't have to worry about it.

Let's take a look at a couple other scenarios. Let's say you have some code that's compiled not with Arc, and you're trying to use it from Arc compiled code. Well, obviously, the compiler doesn't know this, and so in the Arc compiled code, we're going to do a release that's really unbalanced.

And so you're going to over-release this object and not good things are going to happen. Conversely, if you compile the copyleft license code under Arc, it's going to do that extra retain, but the client isn't going to know about that, and so you're going to leak. So what can you do about it? Well, we have two answers for you.

First of all, you can rename your methods. So we could take your unconventional.h file and make it conventional.h. The compiler does name matching based on what we call camel case, which I hope you all know about. So to fix this, what do you do? You remove the hump.

So that you know what's really going on there, or you just adopt the new family of naming conventions for that. Well, I all know that you generally have managers and stuff, and changing names is often something that invites some controversy. So if you can't change the names, we have remedy number two.

And that is we have ownership transfer annotations. And these have been around for a while, in fact. You just apply an NSReturns not retained to methods that aren't actually creating things. And conversely, you use NSReturns retained for those that are. So annotate your header file, and then it won't matter which part of it is ARC-compiled and which part of it isn't. Let's talk about those ownership type qualifiers. We've introduced four type qualifiers to the language, and I want to talk about each one in turn.

First one is strong. Strong variables retain their value. It's the default. You almost never have to type it. Stack local variables, including parameters, are strong by default. What this means is they never hold a dangling reference. They're either nil or point to a valid object. So that solves an amazing number of bugs. The values are released sometime after the last use of that variable.

And so from the intro talk, this is the stack example of POP. When the ARC compiler sees this, what it does is it translates that and adds a retain and an auto-release on there. So if that array was the sole owner of that object, that last object, then we have retained it. We've gotten rid of the element from the array, but it's still valid because we have that retain. And when we return it out, we auto-release it so that you're returning a valid object even if it's now the only reference to it.

Weak variables, by contrast, don't retain their values. They're great for breaking cycles, as you've seen. They safely yield nil when read as soon as the object starts deallocating. and Stack Local Week variables also work this way. So let's take a look at this. Let's take a look at this example of fact in more detail. So let's say you have a routine called Test Week.

You create a new object and assign it into the new object variable, so it's holding the only reference to that object. And then you create a weak reference to it. As you've seen, we use kind of dot dot dot for that. What you haven't seen up to now is that there's actually some bookkeeping that goes on on the side to help make this stuff work.

And so when you do a new object equals nil, the compiler of course releases the old value, so now there's no references to that object. And so that object starts to go away. As part of going away, it notifies the weak system, and the weak system says, "Hmm, yeah, how about that? We have a reference to this, a weak reference to that. Let's clear out that weak reference before we clean up our bookkeeping data." And so it does. The variable on the stack goes to nil, and the bookkeeping data goes away. It works. It's really neat.

Well, let me beat this horse a little bit more. Let's say you create an object and just stuff it into that weak value. Well, what's going to happen here? Well, let's take a look at what the compiler does underneath you. The compiler inserts a temporary, holds that brand new object, stores weak using the primitive, and then releases that temp because that's the last use of that variable. Well, if you think about it, this is exactly the same pattern I just illustrated before. You're releasing the only reference to that object, and of course, this one's going to go to nil also. So don't ever count on weak references hanging on your values.

So, there are a couple things to bear in mind about WEEK, though. It's only available on Mac OS X.7 and on iOS 5. The reason for that is that we've had to tweak the retain-release implementations of pretty much everywhere. And so we can't do that on earlier releases. We can do that on iOS 5, we can do that on 10.7, but we can't do that in the past.

So when we've gone through at Apple and looked at all these custom retain-release implementations, we found out that, wow, we've sped up retain-release so much, and Greg's going to talk about that in the second half, that you really don't need custom retain-release implementations. So we've deleted quite a few of them. And if you're just doing it for performance, you should delete them as well, in all likelihood.

So some classes that are very old have had a little trouble adopting the WEEK system. And so, you know, we've had to do a lot of work on that. So, when we've gone through at Apple and looked at all these custom retain-release implementations, we found out that, wow, we've sped up retain-release so much, and Greg's going to talk about that in the second half, that you really don't need custom retain-release implementations. So an NSWindow, an NSViewController, for example, are two classes you might run into. You can't really form a weak reference to them.

and you'll get a hard crash if you try to. So if you're going to use weeks, make sure you test that code and make sure that you can do that. So another issue is if you're using third-party libraries, you should look to them, especially if you're compiling them, whether they have custom-retained release implementations and just be aware of that. And if you have a case where you need to have a weak reference of some kind and you can't use under-under-weak for some reason, you'll need to use unsafe-unretained as the alternative. So let's talk about that.

So it's an old concept. We've been using unsafe, unretained variables forever. That's what delegates are. That's what @property_assign is doing for you. You use them among cooperating objects to hold safe unretained references. You make it safe by telling all the clients of you, by knowing and telling all the clients of your object that hold these things to clear them out when you go away.

Because the compiler does nothing to help out with unsafe, unretained items, you can actually use them in structs. That's kind of a side benefit. Let's talk about that cooperation thing a little bit. I call it the "dialog dance." So here's a contrived example. Let's say you've got a custom delegate controller. It's got pointers to table view and a do it button set up in IB or maybe programmatically. And in the dialog method, you have to remember to clear them out.

And so you do this. When the last reference to your object goes away, dialog is called, and when you run the setDelegateNil methods, those red, those unsafe references get cleared out, and then the runtime takes care of removing the references from your object back up, and everything goes away and things are fine. Now obviously, if you forget to write a dialog method, or forget to do these set delegate nils, you end up with dangling references in these objects, and that's not really, that's not what you want to do. So it requires more careful programming.

Auto-releasing is the last attribute I want to talk about, and that is -- and that's used primarily for the Cocoa convention of not transferring ownership across parameters. Indirect pointer parameters are treated this way by default, and the basic idea is you just slam a new value on it without worrying about the previous value. So when the compiler sees, say, a KIP method that returns an NSError **, it really treats it as if it was an auto-releasing.

is the founder of LLVM. He's been working on the LLVM system for a long time. He's been Your code, however, might not follow Cocoa convention here. Sometimes, we are told, we've seen code, you return ownership through a method. So if you've got a method that returns or creates an object indirectly, you have to annotate it with the strong directive to say, "Hey, I really want to retain value on the other side of that when I do that." And so you can do that by explicitly declaring it with the strong directive.

So the three primary ones, strong, weak, and unsafe unretained, now have new attribute names for add properties. So we'd like you to think about your object graph in terms of strong and weak links, and if you need to, unsafe unretained. So strong is really just a synonym for retain. Unsafe unretained is a synonym for assign. They both still work and still mean the same thing, but we prefer you to just use strong, weak, and unsafe unretained for this. Let's talk about the copy convention.

So copy with zone is the primitive for creating a copy. And what do you do? You call super to get an empty shell for the new thing, and for every instance variable of interest, you copy the value over. Under arc, you don't have to do retains, you still have to do copies if you need to, and it just works. There are maybe ten people in this room, though, who have had to think about subclassing NSCell. And NSCell can sometimes be a little odd because it uses an NSCopy object. Well, we fixed that under arc as well. So this works with NSCell subclasses as well.

Hmm, maybe more than 10 of you. Exceptions. So the Cocoa Convention for exceptions is they're really bad. If you throw an exception, something really bad happens. In fact, your app is probably going to go down. For recoverable errors, you're supposed to use the convention like NSError **. If you throw an exception, You're often going to leak an object. You can have a retained object, and unless you have a try-catch handler around it, an exception gets thrown, that object gets leaked, and that's also true under Arc. This is a convention we don't want to try to fix because it's expensive to fix. So don't use exceptions.

On the other hand, as you saw with the weak system, you know, we actually keep pointers to stack local variables around, and so we really, even though if you do catch exceptions, we don't want you to crash because the weak system goofed you up. So we make sure that the weak system gets cleaned up under exceptions, so you don't have to worry about that. Let's talk about blocks.

Blocks start out on the stack, and they have to be copied when they're stored into anything that's more permanent, like an instance variable or a global, and when they're returned or indirectly assigned. You have to remember to copy them to the heap, or you have had to remember to do this up till now.

So Arc automates this so that instead of having to remember to do copy-auto-release or copies, you just write the code you want to write. just assign it into an instance variable. are global or returner, and it just works. The bottom line is that blocks work best under Arc, and that's really true.

[Transcript missing]

You form a strong reference to it by just reading it. Strong self equals weak self. And if strong self exists, then you can safely dereference it and tell my view to blank. If you try just doing weak self arrow my view, well, that read of weak self might have lost a race with another thread that just got rid of that.

And it might have yielded nil, and so you might have a crash there. So be careful to always pull and read and use -- don't use arrow messaging with weak variables. So with all that said, with weak references in place, when the last reference to self goes away, then of course the whole thing recovers just nicely, blinking or not. Under-under-block variables have an interesting behavior change under arc. Block objects, like all other forms of storage durations, whatever, are strong by default under arc.

Under non-arc, though, the default is essentially unsafe, unretained. And people have taken advantage of this. I saw this in the lab, I've seen that inside Apple as well. So some people have used an unretained self block variable to do that same trick that I showed you with weak before. So under arc, you have a block object, and you have a block object.

Under arc, with a behavior change, this unretained reference now becomes a retained reference, and it's likely to cause a cycle. So what do you do about that? Well, if the migrator hasn't fixed this for you -- and it does in many cases -- you should try to -- you should convert to using a weak variable instead. And if you can't use weak because you're shipping to an earlier platform, then you can reintroduce that unsafe, unretained behavior. and it will work just the way it did before.

One last topic, Objective-C++ under Arc. Not much to say, it just works. So you can use ownership attributes in your classes. What happens is the compiler generates initializers that initialize the values to nil, that do the retain and the release, or do the strong interactions, and as such, these become non-pod classes, non-plain old data classes, non-trivial destructors and constructors and stuff.

Everything works. Templates work, iterators work, the collections work with the C++ standard library. And the only kind of funny thing is that you have to use the attributes in some places when using containers. And with that, it's time for Greg to come up and talk about Arc Internals.

Thank you, Blaine. I'd like to talk about some details of the Arc runtime and Arc compiler and what it's doing internally. Arc from the inside. So what is Arc? You've heard an awful lot of descriptions of Arc. Here's the best description of Arc. The compiler adds retainer release calls to your code. The compiler optimizer removes some of them. That's really it. That's Arc.

So let's go into a little more detail. This is the last session of the conference, so if you're not tired already, let's make you tired. Here's an example of some strong variable code. You have a method that takes an IVAR and swaps the old value with the new value and retains the old one.

So the Arc version of the code looks like this: no retains, no releases. What does the compiler do? compiler adds, retains, and releases. It retains your parameter, it retains the old value and auto-releases it on the way out, and it retains the new value as it stores it into the IVAR.

What the compiler really adds are C functions. It doesn't actually call the methods. So it calls new C functions in the runtime, but these C functions today just call the methods, so there's nothing interesting going on there. So this is what your code looks like after the compiler frontend is done.

Now the optimizer goes to work. It looks at these retains and says, "Some of these are duplicates. We retained a value and immediately released it." Well, that's dumb. Don't do that. Compiler optimizes your code, removes some of the retains and releases, so your code ends up like this.

Retains the new value on the way in, does the work, auto-releases the one going out, which is what you would have written without Arc anyway. Let's take a look at what the compiler does with weak variables. Here we have a delegate that we've marked weak, and a setter method and a getter method for it. Again, the compiler adds retains and releases for the parameters, adds a retain auto-release for a return value, and it uses runtime functions to read and write the weak variable.

This coordinates with the weak reference system so that you don't read a dangling pointer or write a pointer to an object that's already dying and will become dangling and not be able to read it. This coordinates with the weak reference system so that you don't read a dangling pointer or write a pointer to an object that's already dying and will become dangling and not be able to read it. This coordinates with the weak reference system so that you don't read a dangling pointer or write a pointer to an object that's already dying and will become dangling in a minute.

Of course, when the optimizer goes to work, extra retain-release goes away. The compiler knows that load-week already returns a retain-auto-release value, so it doesn't need to retain auto-release again. Optimizer's smart, and your code looks really simple like this. So this is the code you would see if you looked at the generated code, if you traced through your code in the debugger. These are the functions you'd end up with.

One final case. Let's look at NSError. NSError, we have a method returning an NSError value to an ARC caller. What does the compiler do with this code? Well, remember what Blaine just said. NSError variables are implicitly auto-releasing. Stack variables are implicitly strong. We release the strong value when the method is done. And if this was all the compiler did, you would crash.

You have the auto-released error value. The compiler decided it also needed to release it again. And that's an over-release. It doesn't work. Luckily, the compiler does not do this. The compiler adds that. It adds a temporary auto-releasing variable to catch the value coming out of the method. Then it stores that value into the strong stack variable and retains and releases it.

So the upshot is, even though there's a mismatch between auto-releasing and strong, the compiler is smart enough to paper over it, patch up the problem with a temporary variable, and you don't have to think about it. You just write this code, it works. Fine. NSERA works great. If you want to be extra double special clever, you can write this.

You can explicitly mark your stack variable auto-releasing. Now the compiler doesn't need a strong temporary, doesn't need the extra retain and release. So if you are having a little bit of performance trouble, which you almost certainly won't, you can add this sort of cue to the compiler to help it know exactly what you want to do.

So, we've added a lot of runtime functions that the compiler will add to your code. You'll see these in your disassembly, you may see these in backtraces or while debugging. The basic memory management calls, of course, retain, release, auto-release. They just call the methods. The Week Reference System: Load Week and Store Week to read and write week variables.

Some other calls you might see. The NSObject implementation now lives in the Objective-C runtime. So the implementations of basic NSObject methods, basic root class methods, which is why it's called root alloc, root retain, and a half dozen others, will now show up in backtraces and in instruments traces. The AutoreleasePool implementation is also now in the Objective-C runtime with the AutoreleasePool push and pop functions. When you write @autoreleasepool, that's what it looks like.

And finally, there's a set of functions much longer than this list, which are optimized versions or combined versions of some of the functions, some of the basic operations. There's an optimization for auto-released return values, which I'll be talking about later. And it uses functions like auto-release return value and retain auto-release said return value. And there are other optimizations for doing a retain and a store or a retain without releasing the previous value, things like that. There are lots of these things. We'll be adding more in the future. Don't freak out when the compiler adds them to your code.

Of course, most of these functions are not for public use. They're for the compiler to use. They're not declared API. So some of these functions you can use directly. The others, don't call them. If you do, the compiler may transform them. Because the compiler thinks it knows what's going on and thinks that it called them itself. So be careful about that. Use the public API. Don't use the stuff that you see in the open source runtime directly.

Arc modifies the destruction of objects. So let's look at what happens when an object dies. Of course, Arc releases your IVRs and properties automatically for you, and it also erases weak variables automatically. So it's modifying the deallocation process. Let's look at everything that happens to an object as it dies. We see the timeline of what happens during the death of an object. Let's look at these in detail. The first thing that happens is release is called, and the retain count goes to zero for the very last time. The object is now deallocating. It will die.

Since the object is deallocating, we don't want to create weak pointers to it anymore, because you'd end up with a dangling pointer when you're done. So the release method tells the weak reference system, "This object is dying. Don't do any weak references anymore." And then the release method calls self-dealloc, the normal thing.

Self-dialog starts the dialog chain, starting with the subclass dialog. If you wrote a dialog method, this is where your code gets called. If this is a non-ARC subclass, this is where their dialog method would be calling release methods and delegate clears and things like that. Each subclass calls superdialog, we walk up the superclass chain, and we eventually get to NSObjectDialog.

NSObjectDialog simply calls the Objective-C runtime to tell that the object is dead. It goes through actually a couple of different function calls here, but you end up in ObjectDispose. ObjectDispose does the rest of the destruction work. C++ IVARs are destructed, Arc calls its release method here, and associated references and weak references to this object are cleared. The point to note on the ordering is: The destructors and the Arc release are called after your subclass dialog is called.

So in your dialog methods, you can still use your C++ IVARs, you can still use your Arc IVARs, because they aren't dead yet. They only die when the dialog methods are all done, and NSObjectDialog calls the runtime to kill it. Finally, Object Dispose calls us free. And I hope you all know what free does. But this is the final process to destroy the object, reclaim the memory. It's gone for good now.

Let's talk about Arc adoption. You've seen in some of the intro talks, some of the other talks, about what your code must do to adopt Arc code. You might have to modify how the migrator can help you do it. There are some low-level tasks that some of you writing core foundation code, for example, also need to modify, and the migrator does not generally help you here. So low-level tasks include core foundation usage may need to be modified. If you have a custom retain-release implementation or a custom weak reference system, those also may need to be adapted or removed in order to work with Arc.

Let's look at core foundation. Arc automates Objective-C. It does not know about core foundation code, does not understand core foundation types, does not understand core foundation memory management conventions. So if you use core foundation code or core foundation-like objects like the address book framework or core graphics objects, you need to help Arc understand the memory management that's going on so it correctly manages the memory of these sorts of objects as you use them.

Let's look at an example of what goes wrong if you take unmodified core foundation code and try and use Arc. Here's a simple example we're calling an address book function that returns a retained core foundation string. It has "copy" in the name. That's core foundation "e" for "returns a retained object." We are casting it to an NSString and assigning it into an IVAR. So, looks okay for Arc. You know, we should get automatic memory management.

Except that Arc doesn't know what that copy does. So, Arc adds a retain and release because the NSString variable is strong. But it didn't know that there was a copy call. It doesn't know there's another retain in play. So, we end up with two retains, one release, and a leak.

So, unmodified core foundation code may leak, like that example. Or, other code, it'll actually crash. Or, if you're very lucky, it may run correctly. Now, it would be really hard to go through your code and find every single place where you're using core foundation, like trying to find that cast to NSString. That would be hard. So the compiler helps you out. The compiler helps you out with compile errors, because the compiler's good at that.

Any toll-free bridge cast from a core foundation type to an Objective-C type is an error with the ARC compiler. It is disallowed. Can't do it. Well, most. There's one exception which I'll show you. But most of the time, it disallows them. So this is your cue at the points of these errors. There's Arc code with core foundation usage.

You need to go through and modify the code, modify the cast to tell Arc what is going on. So there are three cases, three different recipes for how to modify your code depending what you're doing with the CF object. First case, we have a method that returns a core foundation object and you didn't use any other core foundation memory management. You just method return an object to you, you use it, you're done.

Second case is similar. Again, no CF retains or CF releases or creates or copies in your code, but the value came from something other than a method return, like the address book function we just saw. The final case is where you are calling CF memory management. You created a CF object yourself, you released it, something like that. So those are the three cases. Let's look at the first one.

Core Foundation values returned by methods. This is an iOS example of the UIImage class, which has a method that returns a Core Foundation CGImageRef. Okay, fine. We call it, we cast it to ID because we want to store it into an array. So this is a case where we have Arc code, Core Foundation code. How does it work? The good answer is, in this case, it works unchanged.

Arc knows that this was returned by a method. Methods have Cocoa naming conventions, with Arc knows everything about Cocoa naming conventions. So it knows that this Core Foundation object was returned, auto-released in this case, or copied in other cases, and so it knows what memory management to apply to the toll-free bridge flavor of the CF object that we just had. So this case is a little bit different. case works. Don't have to think about it. No compile error.

So, simple cast if you got a value from a method and you aren't using other CF memory management. Second case, we have a core foundation value they got from something other than a method returning a CF type. Here we have two different flavors of read an object from array, convert it to the other toll-free bridged flavor, and use it as is. No memory management, but no Cocoa convention method returning a CF type. So here, the compiler tells you you have CF code. You may need to modify this memory management behavior, so it will give you a compile error for these two casts.

You don't want any memory management. You just want to use the object as is. Somebody else is retaining it. Just do it. The way to say just do it to the compiler is to tell it, "I'm doing a cast which is bridged." This is a bridge cast from core foundation type to Objective-C type or vice versa.

So, again, no CF memory management involved when you use Bridged. Of course, Arc may retain and release the NSString, but you don't care whether it does that. That's Arc's problem. That's not memory management you need to worry about. So that's the second case. If you have no CF memory management, then either it works out of the box, or you need to modify your cast to say it's bridged.

The final case where your code wrote CF memory management stuff. For example, that address book function again, which is a copy function. This is the old code, pre-ARC. You copied it as a CF value, moved it across the toll-free bridge, and auto-released it. Well, of course, this is ARC.

We don't have auto-releases anymore in your code. So now we have an unbalanced copy. ARC doesn't know it's there because it doesn't know about core foundations memory conventions. So how do you modify your code? Well, you have a copy. You should balance it with a release, right? Right. you use a CF bridging release.

CF Bridging Release is a CF release. It balances a previous CF retain or copy or create CF function. And it also safely transfers the value to Arc. So Arc will, of course, retain or release the value as it sees fit. And the CF Bridging Release balances the core foundation copy operation. So it's really easy. You just write code where retains and releases balance. Copy and release is fine. And use the Bridging Release to hand the value to Arc when you're done.

Going the other direction, where we have a copy method, we converted it to a CFString, and then we CF released it. Again, Arc knows about the copy method, but it doesn't know about the CF release, so we need to balance the CF release with another retain. And that looks like a CF bridging retain. It's just the opposite of a CF bridging release.

CF Bridging Retain is balanced by an explicit CF release in your code, like this one here. That one up there. Whichever screen you're looking at. It also safely accepts the value from Arc, so it makes sure that Arc doesn't delete that copied value before we've got it handed over to CF's responsibility. So this is the ownership transfer that you need to use going in and out of toll-free bridge code if you have Core Foundation Memory Management.

So that's the third case. If you have Memory Management and you're moving code in and out of Arc, then use a CF Bridging Retain or a CF Bridging Release to match the other Core Foundation Memory Management you already have. There's one slight caveat to everything that I just said about Core Foundation.

The WWCC compiler does not implement any of what I just said. It still has the cast as an error feature, but it uses a different set of functions for handling memory management transfers and telling Arc what is going on. So if you go to the Apple developer website, look up the Programming with Arc Release Notes, it will have two sections on how to manage CF objects and how to manage CF objects with the WWDC compilers and tools. In the future, in the next seed release, some future release, you will get what I just said, and you can go back and watch the video again and convert all your code to use that instead.

Other low-level things you may need to modify. If you have custom retain and release methods, they must be adapted for Arc. The problem is the release method and the weak reference system need to coordinate in order to avoid race conditions when an object is being destroyed and you're trying to read a weak reference pointer to the same object. The release and the weak reference system need to have multi-thread synchronization to make sure that weak system works correctly. If you have custom retain and release implementations, they therefore must evolve or die.

So if you wanted to evolve your custom weak reference system, there are two new methods you need to add. You need to change most of the rest of the methods. There are subtle race conditions. It's actually very difficult to do any of this correctly. Depending what your custom retain and release do, there's no simple recipe. It depends if you're using a local IVAR or if you're using it to do teardown or if you're using it to do special singletons.

Short answer is we don't recommend it. It's possible to modify a custom reference system until it works with weak. We don't recommend it. It's hard. We did it a bunch of times wrong inside Apple before we figured out how to do it right. We're pretty sure it's right now.

We recommend something else. We have two other recommendations. First recommendation, delete your custom retain-release implementation. NSObject's retainer release is much faster. If yours existed for performance, you may not need the extra performance anymore with faster machines and faster NSObject code. If you had custom teardown logic, you were releasing stuff when your retain count dropped to three, for example, real code does this. Don't do that anymore. Use weak variables in Arc to do the teardown logic you need instead.

If you have a singleton pattern using custom retainer release, use a simpler singleton pattern that doesn't have retainer release anymore. So, recommendation one, delete it. There's one other benefit to deleting your custom retainer release, is that future improvements to retainer release performance are likely only to apply to default retainer release, not custom retainer release. So we may make it faster and leave you behind. So, delete it.

Recommendation number two, if you really do need your custom retain-release system still, you can disallow weak references to your class. You can write this method, allows weak reference return, no. In this case, if somebody tries to form a weak reference to your object, you'll get a crash instead.

So, a much simpler transformation if you do need your retained release system and you don't need to use weak references. If you want to keep both, it's really hard and I'm not going to explain it here today. The last advanced thing you may need to modify are custom weak reference systems.

We know several of these things exist in the wild. We found, I forget how many, in Apple's own frameworks of weak reference systems, some of which were actually mostly correct. Mostly thread safe, mostly didn't crash if dalloc called retain and release again, that sort of thing. So, one way to adapt your weak reference system is to replace it with Arc. Use Arc weak variables instead of your weak reference system. Well, that's easy, that's good.

If you like your weak reference system, if you have a bunch of code using whatever your API is, you can always rewrite it. Modify the internal implementation of your weak system to use our API, the load weak and store weak functions that I mentioned earlier. These are public API that you can use to interface with Arc's weak reference system. In non-Arc code, I should say. If you have Arc code that tries to say "load weak," compiler will not like you very much.

So here's an example if you were going to modify your weak reference system. Here we have a getter and a setter and a dealloc method for a weak IVAR in non-ARC code. We can use the loadWeek function to read it, the storeWeek function to write it, and this is very, very important, the storeWeek function writing nil when the variable goes out of scope to clear the weak reference machinery and make sure the weak reference system doesn't write a nil to that address sometime later. So this is how you would modify a weak reference system or some weak variable if you outside your ARC code.

Let's look at performance. Performance is, of course, really important for everyone. And it's also important for Arc because for some code, we're adding more retains and more releases than the same manual coded code might have had previously. So we've improved performance with a lot of the primitives. Retain and release. Arc uses retain and release. Everybody else uses retain and release. We made it faster. We made it a lot faster in Lion and iOS 5.

Autorelease pool. Autorelease pools get used quite a bit. There are a lot of loops and code, things like that, that try and go out of their way to use a few autorelease pools instead of one every iteration. Well, we didn't like that. We said, first of all, we can make NSAutoreleasePool faster, and we did that. And then we said, at AutoreleasePool, we can make it way faster. It's way faster because it doesn't need an AutoreleasePool fake object. It doesn't need obcmsend alloc init drain. So the @AutoreleasePool construct is about six times faster than the old NSAutoreleasePool alloc init was.

So the moral of this slide, if you have a loop that's, you know, you're trying not to use auto-release pools, just throw them in. It's cheap. It's like as fast as a function call now. Last example I want to show you for performance is auto-release return values. We've made this faster. Let me explain what I mean. This code has a getter method that returns an auto-release result, and we have a caller which is calling the getter method and retaining the value it got back.

Well, we have this auto-release which immediately gets retained again. This is just extra work. This is just trying to get the interface so it's clean. We don't have to think about memory management. But the auto-release and retain are wasted, and the object lives longer than it might have to because it's in the auto-release pool. And on iOS, we tell people don't auto-release if you don't have to because there's that extra cost. We can do better, and we have done better. The Arc compiler will write this code this way.

Two Objective-C runtime functions: auto-releasing a return value is a specialized function, and retaining a return value that you got auto-released. Two separate operations that coordinate to optimize it. The actual implementation is really cool. It's really clever and I wish I had thought of it, but I didn't. These two functions, the function in the getter method looks up the call stack to see what the caller is about to do with the value that it just retained.

If these two functions see each other on the call stack, then we optimize it. The return value is saved in thread local storage for the other function to see, and we don't auto-release and we don't retain. That's a really good optimization. What if you have mixed code where only some of it is built with the ARC compiler? You might have this.

The getter method has the optimized function, but the caller is just calling retain because it's not ARC. What happens then? The two sides look for each other, and the caller says, the getter method says, "Whoops, this guy doesn't know what I'm doing. He's not smart. He's not optimized. So I'll do the old thing." No optimization, just call, auto-release, and retain as usual.

So if we have the caller and the callee are both arc or they're both properties, then the optimization will kick in. And what happens? It gets something like this much faster. The first chart -- It's great. The first chart is the expense of the extra auto-release and the extra retain.

And of course, the optimized code, just looking at the memory in the stack, stuffing in thread local storage, that's really fast. So in the optimized case, the extra overhead of auto-release retain is just gone. So as more people adopt Arc, the optimization will kick in in more places. So we're really looking forward to that.

And that's Arc in Objective-C, Automated Reference Counting with ownership qualifiers so you think about your object-graph's relationships rather than retain-release. If you have low-level memory management like Core Foundation, you may need to adapt. And Arc has costs for some code, but we have performance improvements to balance some of the costs.

For more information, definitely visit the Programming with Arc release notes on the developer website. If you have questions, we don't have time for QA today, but you can find me on the Apple Dev Forums under the Developer Tools sections, or you can contact the DevTools evangelist, Mike Jurowicz, at the email address shown. Related sessions and the videos you may want to watch, the Arc intro session, of course, more details about Blocks and Grand Central Dispatch in practice, and, of course, Arc is LLVM only, so move to the LLVM compiler, visit the session there. Thank you.