Showing posts with label Objective-C. Show all posts
Showing posts with label Objective-C. Show all posts

Thursday, August 30, 2012

Cover up those ivars

It all started with a tweet a couple mornings ago...

I completely agree with this. Objective-C has evolved over time from where everything was public and had to be included in the header files to now where only the bare minimum needs to be exposed in the header file. Now its completely bad practice to put anything in the header file that doesn't need to be exposed.

There are several Good reasons for this

When designing a class from an external point of view all I should really need to know is what your class name is and what its api's are, what I need to pass them, if anything, and what they return. When you see internal implementation details and variables there is a temptation to use them. This is bad, because you as a consumer of the class should only be concerned with what the class promises to do, and when you reach into the class to access stuff that was never really intended to be exposed you will be bitten with bugs if the implementation details ever change.

I think of methods as fulfilling contracts, I agree that I will pass them what they need if they accept arguments and they agree to return something or cause some effect (i.e. NSLog() piping text to console,etc.) As a writer of classes in a Framework, i've never been concerned about completely changing the details of how the classes work, because I have Unit Tests that test these contracts with my methods to make sure they work as advertised. It's also just cleaner design-wise and the more you can leave out of your header file the better, it makes the header file easier to read and scan for what I am looking for.

How do you do this?

Ideally the rule of thumb should be this: Expose as little as you possibly can in your header file!

This means several things: (1) If you can not declare methods in the header and instead declare them in a class extension in the implementation file(.m) do it (2) If you need to expose properties make them readonly if possible (3) if you need to have ivars declare them right after the @implementation declaration. This doesn't mean hide everything all the time, but generally I like to think of this as designing a class and then only putting in the header file what needs to be exposed to make the class useful.

Here is a class extension

@interface MyClass()
-(NSUInteger)somePrivateMethod;
@end

Here is an example of declaring a method in a class extension. Class extensions are like categories, except that a class extension really just extends the @interface section of a class declaration in another location, so unlike a category if you declare a method and forget to implement it, the compiler will warn you.

If you need to declare properties try to hide them in your extensions, if you need to make them public, make them readonly if possible. This still gives people access to them, but prevents them from doing anything with the variables and screwing up your class. Like so

@interface MyClass : NSObject
@property(readonly, retain) NSString *currentPath;
@end

then in your implementation file you can redeclare it with read & write capabilities. 

@interface MyClass()
@property(readwrite, retain) NSString *currentPath;
@end

This way, publicly you can give people access to bits of information about your class, but only have rights to change them in the implementation. You can also use these extensions to declare properties that are only used in the implementation file.

Another way of declaring variables that didn't exist till very long ago is to do so only after the @implementation declaration like so

@implementation MyClass {
    NSString *internalVar1;
    NSNumber *internalVar2;
}

this is equivalent of 

@interface MyClass : NSObject {
    NSString *internalVar1;
    NSNumber *internalVar2;
}

@end

 except now that this isn't in your header file polluting it. 

How do my Subclasses use these vars?
A legitimate question that someone asked me this afternoon was essentially "If my class hides all these variables in extensions, how could I ever use them in subclasses?" Thats very worth asking. In this case instead of declaring these variables in a class extension in the implementation file you would create a "MyClass_private.h" file where the class extension is. Then your .m file and any interested subclasses can import this header in their implementation files and use it. I would even go so far to write methods into your class such, that to the extent possible, you don't even need to access these internal only vars in your subclasses. 

Why Does this matter if its code just for me?
A couple people asked me this. All I can really ask is why would you write bad code just for yourself? Nobody writes perfect code, well maybe except for me(I kid I kid), but you're not me. But why would you write intentionally bad code for yourself? I always write my classes using these principals, even for stuff thats just for play. Well designed classes means not having to spend tons of time ripping & rebuilding them just to make them presentable later on, it means you can instantly take them and use them in anything without much worry. 

In Conclusion
The less you expose in your headers the cleaner they are, they become easier to read, they don't expose anything that could become future bugs or crashes later on. This makes it easier for you to completely rewrite or change implementation details at will.  

Follow Up
Rich in Comments makes a good point about also putting IBOutlets & IBActions in class extensions. When I said to hide vars and methods I also meant these. The IB component in Xcode iirc didn't see those initially. However for a while now it can see IBOutlets and IBAction methods declared in Class Extensions.

When I said that some of this is "new" in this article, generally I mean in the grand scheme of Objective-C's history at Apple it's new.

Eric made a good point, and I saw and forgot about this in the WWDC videos, that in LLVM Compiler 4.0 its no longer necessary to declare private methods as the compiler scans the implementation for those methods and thus won't give you an error if you forget to declare it.

I was asked if I put my ivars in a class extension or declare after the implementation, generally I declare them in my class extensions.

Tuesday, December 28, 2010

Objective-C Memory Management & Garbage Collection

This article started out as a presentation I did for the Des Moines Cocoaheads.

Introduction

Objective-C Memory Management is something i've seen new people to Cocoa & Objective-C mess up in ways I could just not conceive of on my own. In reality Objective-C memory management is not that hard. You simply need to be aware of some rules and follow a couple of good development practices. Good memory management practices are a good thing to follow on any platform. You don't want to be known as "that" app that hogs lots of memory, I have switched to alternative apps a couple times because the apps I was using were fine, but consumed far too much memory. Especially on iOS you need to follow good memory practices, because otherwise you'll be struggling to deal with low memory alerts and the possibility of your app being killed by iOS.

Objective-C Retain Count

Objective-C in retain count mode (not using garbage collection) is a simple idea. When you explicitly allocate an object it gets a retain count of 1 and when you call release or autorelease on an object it's retain count gets decremented and then the object will be collected. It is the only mode available on iOS Devices and has been in use on Mac OS X since the beginning of the OS.

NSObject *object = [[NSObject aloc] init]; //retain count 1
[object release]; //retain count 0

When a object gets released -dealloc gets called on an object and its memory will be reclaimed. It's important to note that you never call dealloc on an object directly. In fact in all my time as a Cocoa Developer I've heard only 1 legitimate use of calling -dealloc on an object directly, I won't say what it is, but needless to say you would have a lot of Cocoa/Objective-C experience behind you before you would even conceive of doing this. In the same area as -release there is also -autorelease. -autorelease is the same as -release except that it'll perform the release in the future. This works great because with this an object you know you need to release in the future can be taken care of at the beginning of a method or section of code.

-(void)doFoo:(BendingUnit *)bender
{
 if(flexo)
  [flexo autorelease]; //will be sent release later
 ...


Owning an Object
In all these cases when we explicitly perform an -alloc we "own" the object, and when we call -release or -autorelease we relinquish ownership. If you call a method whose name contains 'alloc','new' or 'copy' or if you send a retain message to an object you now own the object and it is your responsibility to send it a -release or -autorelease at an appropriate time. An example of assuming ownership of an object...

-(NSInteger)numberOfInstancesOfString:(NSString *)pattrnString
{
 NSString *patternString = [[pattrnString retain] autorelease];
 NSInteger count = 0;
 // do some stuff here with the string return count;
}

In the above example we are doing something very wise. We are passed in a NSString object which may live beyond the scope of our method. So to ensure that the string lives throughout our method we are calling -retain on the string object and -autorelease on it as well so that at the end of the method it'll be restored to the state it was originally in. If this is a normal string object (retain count 1) then all we are doing is incrementing it's retain count to 2 and then at the end of the method it's retain count will be back at 1. However if we are in the middle of executing this method and somewhere else this object gets a release message then we are ensured to be able to use the object for the lifetime of the method and then the passed object will be released. Note that by calling retain on the string object we assumed ownership of the object and then also did the responsible thing and called autorelease to relinquish ownership of it at the end of the method. What happens we we don't follow the rules?

-(void)dooFoo
{
 NSString *myString = [[NSString alloc] initWithString:@"Good News Everyone!"];
 //... do some stuff
 //... oh noes we are at the end of the method and never sent release to mystring!
}

Oh Noes! At the beginning of this method we create a NSString pointer and explicitly allocate memory for a NSString object and initialize it with a NSString object. The method does some things and then it goes away. However the memory that we allocated is still there, but we no longer have a reference to that memory leaving it forever uncollectible (except under Garbage Collection.) This is a memory leak, it's memory we asked the operating system to set aside for us that we can not reclaim.


NSAutoreleasePool

Autorelease pools are a place where you can collect objects sent an autorelease message and clean them up by sending an NSAutoreleasePool a drain message. When you are running an application based on AppKit, the Cocoa Framework automatically creates a NSAutoreleasePool instance for you and drains it upon your application quitting. You can setup and drain a autorelease pool easily.

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *temp = [NSString stringWithString:@"Name:"];
NSNumber *tempNumber = [NSNumber numberWithInt:55];
[pool drain]; //collects temp & tempNumber

You can also do AutoreleasePools within other autorelease pools
int main(int argc, const char **argv[])
{
 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSArray *files = //fileArray...
 for(NSString *file in files) {
  NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];

  NSError *fileError = nil;
NSString *file = [NSString stringWithContentsOfFile:file encoding:NSUTF8Encoding error:&error];
  //process file...
  [innerPool drain];
 }
 [pool drain];
}

This can be convenient, especially in iOS to allocate a bunch of objects and free them as soon as possible with an autorelease pool to keep memory pressure down. In some cases they are completely necessary if you intend to say work with Foundation in a command line tool you have to explicitly create an autorelease pool, the same goes for NSOperations main method (except for Garbage Collected apps where this is done automatically for you.)


Coding Horrors

A while before I made a presentation from the same content that is in this article I asked on twitter for some ways people had seen memory abused in Objective-C. From the responses I got back and some things I have heard from various people I won't name here a lot of people have abused Objective-C memory in odd ways. I want to feature some of them here in the hopes that you will never commit these atrocities yourself.


Exhibit 1
-(void)dealloc
{
 while([myObject retainCount] != 0){
  [myObject release];
 }
 [super dealloc];
}

This is wrong on all sorts of levels. Putting this in your code is a sure fire way to show someone how little you understand about Objective-C. First of all let me say this morvo_retain_count.png

If you've been dealing with Objective-C for a while you know that you shouldn't be using the value of retain count, it never actually goes down to zero and you should never be testing against zero anyway. In fact the only reason retain count is still in the Cocoa framework is for legacy reasons and there are a lot of developers petitioning Apple to remove retain count from Cocoa entirely. In any case, the above code should only have 1 release per object in it. If you have objects that have a retain count of 1 or more by the time they've hit this method then you have not properly released or autoreleased the object somewhere else.


Exhibit 2
MyObject *obj = [[MyObject alloc] init];
//do stuff with obj...
[obj dealloc];

Again you shouldn't call dealloc on an object directly. In fact in all of our Cocoaheads group only Eric Rocesecca (a longtime mac veteran, formerly of startly (quickeys) fame) could only come up 1 use for sending dealloc directly to an object for 1 specific case. I won't even go into that specific case, because it's really a specific niche case & beyond the scope of this article.


Exhibit 3
MyClass *obj = [[[[MyClass alloc] init] autorelease] retain];
//do stuff with obj...
[obj release]; 

In this specific example by itself the extra autorelease and retain are just extra garbage at the end since you could just have the alloc and init and do the release and have the exact same effect. This code was shown to me to be in some of Facebooks open source code.


Exhibit 4
MyClass *myObj = [[MyClass alloc] init];
//...do stuff
[myObj release];
[myObj release]; 

If you have multiple retains/releases in 1 place its a very strong signal that you have not done a proper retain release somewhere else. You should really examine your code to make sure you should be doing retain and release elsewhere.


Exhibit 5
NSAutoreleasePool *pool = //...//... do stuff
if(num != kMax)
{
 NSAutoreleasePool *pool2 = //...
NSString *myStr = //...
 //do stuff with myStr
 [pool2 drain]
}
[pool drain]; 

This is something that I could not have conceived on my own. If you are using a lot of autorelease pools and using them as a fix for memory leaks your doing something wrong. There is a legitimate use to using autorelease pools every so often as a means of releasing memory pressure, especially if you are allocating a bunch of objects at once on iOS, but you shouldn't be putting them everywhere because you detect a memory leak.


Exhibit 6
[self dealloc];
while([self retainCount])
 [self release]; 

Similar to Exhibit #1, except with 2x the stupidity. So how do we find what's wrong with our apps?

instruments_memory.png

There are several things you can do
1. Turn on the Clang Static Analyzer, I basically duplicated by debug configuration and named it Analyze and then flipped on the "Run Clang Static Analyzer" checkbox so it's always running the clang static analyzer all the time. The Clang static analyzer will point out many (but not all) places where it can see you are doing something wrong with memory
2. Periodically profile the memory use of your app
3. Run Zombies instrument on your app to track down messages sent to deallocated objects

Objective-C Garbage Collection with AutoZone (libAuto)

Starting in Mac OS X 10.5 we got automatic memory management on Mac OS X with AutoZone (aka libAuto) with 2 collection modes generational and full. Starting in Mac OS X 10.6 we got an additional mode called local. Garbage Collection works on an entirely different principal than retain count. Essentially what you are doing in garbage collection mode (gc) is trading a little bit of cpu time for the sake of letting libauto collect objects that are out of scope and no longer referenced. At this time garbage collection is only available on the Mac. There has been speculation on when it might be made available on iOS, but I suspect that it'll only become available once the low end of all supported iOS devices are running at least the Apple A4 chip, which means the iPhone 3G and iPhone 3GS would all need to be phased out before this is feasible.
Apple has described AutoZone as
"libauto is a scanning, conservative, generational, multi-threaded garbage collector. "
This means several things. The basic principal of libauto is that from time to time it will scan the memory in use by your garbage collected (gc) app and collect out of scope memory. It is conservative in that Apple has said that when big events (like a user begins typing, massive cpu starts going on, etc.) libauto will just back out and stop collecting rather than possibly slow your application down during critical events. The generational part of this is actually how libauto began scanning your app when version 1.0 came out in leopard, it had 2 modes generational (intended to run frequently) and full (slower and to be run less frequently than generational) and now in 10.6 Snow Leopard we have local. I'll go into how these modes work later on. LibAuto is also language agnostic, it is not intended to just work with Objective-C & C, it is also in use in Ruby via MacRuby right now. Additionally libAuto is open source you can browse the source code from here http://opensource.apple.com/source/libauto/libauto-141.2/ and download a zip file from http://opensource.apple.com/release/mac-os-x-1065/.

Garbage collection is nothing new. Many other programming languages such as Ruby, Javascript, Python & Java have had garbage collection for a long time now, but no 2 garbage collectors work exactly the same. When we go into using garbage collection suddenly having to remember your retain & release messages become a thing of the past, instead you become concerned with having references to all objects you need and if those references are strong or weak. Many people have asserted that the same apps under garbage collection are generally less crash prone. Many apps already use Garbage Collection such as Xcode, Interface Builder, Mac OS X System Apps, Rapidweaver, etc..

How libAuto works

libAuto works on a fairly easy concept, at various points during your applications run on a background thread it will scan your applications memory for out of scope memory and collect what it can. You can think of it on a simple level like so
gc-diagram-1.png
We have an application with many points of memory allocated and some that have been allocated, but are no longer referenced by anything. Additionally I put in a weak reference in this diagram which I will go into more detail soon. What libAuto does is scan your application for root objects and then follows the strong references from those objects to all the other objects it can reach. When it's done it knows all the objects that are reachable from the root objects in the application and marks all the non reachable objects for collection. LibAuto then comes in and collects them. It has 3 modes it works in when scanning your memory and collecting objects.

Generational Mode
This is the mode that was used most often on Leopard. It works on the assumption that most objects are temporary and die young, and so the collector will try and focus on the young objects and not the long lived older objects in the app which have less likelihood of needing to be collected.

[NSDateFormatter setDefaultFormatterBehavior:NSDateFormatterBehavior10_4];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:dateFormat];
NSDate *returnedDate = [formatter dateFromString:dateString];

return returnedDate;

In this example the purpose of this code is to return a NSDate object. However in the process we create and allocate a NSDateFormatter object. The DateFormatter object is only there temporarily for the purposes of being able to set a attribute on it and then have it create another object from that (our NSDate object) and then we basically just ditch the NSDateFormatter object. When the garbage collector comes along it will notice that the NSDateFomatter was allocated and collect it. You probably do this a lot in your code, basically creating temporary objects in the process of accomplishing the task you are trying to achieve.


Full Mode
Full mode pretty much works as you would expect, it runs through all memory on your application and does a thorough collection. It takes the longest amount of time and so therefore doesn't run as often compared to the other modes.
Up until 10.6 these were the only 2 modes in libAuto. In 10.6 we gained a new mode called local.


Local
local mode works on an entirely different principle than the other 2 modes shown so far. This mode only scans 1 threads stack for variables between 1-96 bytes which is supposed to account for a majority of the objects in use according to Apple. Because it's not scanning your whole app and is only focusing on 1 thread it is much quicker than the other 2 modes. It will not scan Core Foundation objects which have a retain count of 1, you'll need to do a CFRelease on Core Foundation objects to make them eligible for collection.

Working with the Garbage Collector

Now we have a basic understanding of how the garbage collector works, but there are some things we still need to examine before we really have a full understanding of how to work with the garbage collector.


How to trigger the Garbage Collector
The garbage collector class is NSGarbageCollector. The 2 most common methods you will probably use are -collectIfNeeded and -collectExhaustively. The idea is that you being the architect of the app you are working on, know the best points when your application is running to trigger the collector. So for instance you may trigger a bunch of code to be run on startup in -awakeFromNib and you know 1 or a few possible points at which the arc of events in the apps startup will end and at those points you may wish to signal to the garbage collector that you have good points at which nothing is going on and the garbage collector can go through your app and collect memory.

-collectIfNeeded - Use this to suggest to the garbage collector that now is a good time to go and collect memory in the application
-collectExhaustively - Use this to force the garbage collector to collect memory in the application

Again even though you may suggest to the garbage collector that it should collect memory it may at anytime stop collection because of things like the user beginning to interact with your application.


Foundation Tools
In Cocoa apps the garbage collector thread is automatically started for you. However in foundation tools you need to manually start up the garbage collector by calling objc_startCollectorThread(). You can also use the method objc_collect(OBJC_COLLECT_IF_NEEDED) to trigger the collector. Apple also suggests if you do this that you call objc_clear_stack() to make sure nothing is falsely rooted on the stack when doing foundation tools.


__weak
The __weak qualifier is needed to solve a very important problem. If you have 2 objects pointing to each other and at least 1 of those objects has a strong reference to it, then those 2 objects will never go away because as far as the garbage collector is concerned they are reachable through root objects & strong references and therefore not eligible for collection. By default all references are strong references so simply having a pointer to other objects makes them visible to the garbage collector and thus not eligible for collection.
Screen shot 2010-12-22 at 2.06.47 PM.png
These are both objects which have valid strong pointer references. The 2nd window may have had another object reference it at some point in time but that object stopped referencing it and now you have a pointer to it, but you don't necessarily need to keep that reference alive. __weak solves this by allowing you to still have a pointer to the object, but qualifying it with weak so it just nils out when it goes away
gc_windows2.png
this way with weak references the 2nd window becomes eligible for garbage collection, you still have a reference to that object, and when you try and send messages to it they just go to nil  and if you check that pointer you'll see it points to nil assuming it has been collected. This has other benefits, in Mac OS X 10.6 and later NSNotificationCenter is weak referenced so you no longer need do to the following in your code

[[NSNotificationCenter defaultCenter] removeObserver:self
      name:kObservationName
      object:nil];

that's right since notifications are weak referenced you no longer need to remove yourself as an observer from them under garbage collection.


NSMapTable & NSHashTable
Under garbage collection all references to objects are considered to be strong by default. As a result of this you have to either explicitly make references weak by using __weak or by using a class specifically configured to use weak references. These classes include NSHashTable which is a class modeled after NSSet to support weak references, or NSMapTable which has been modeled after NSDictionary to support weak references.


Say goodbye to -dealloc, Say hello to -finalize
Under garbage collection the garbage collector will send the -finalize message to objects instead of -dealloc when collecting them. Most of the time this may not even be necessary to implement this as you will mainly just need -finalize for letting go of external resources like say closing files. In much the same way you'll call [super dealloc] at the end of -dealloc you will also need to call [super finalize] if you need to implement finalize. Additionally your finalize methods need to be thread-safe.
-(void)finalize
{
 if(myFileRef != NULL) {
  //close file
 }
 [super finalize]; 
} 
Making malloc'd memory collectable
There are times when you need to manually allocate memory through malloc or other such functions. Unfortunately the garbage collector does not automatically pick up on memory allocated like this. In order to remedy this Apple has provided the function NSAllocateCollectable().


Core Foundation & Garbage Collection
There are times when you need to dig down into Core Foundation to get functionality not found in the Cocoa Frameworks. As such Core Foundation will have to work with and interact with the garbage collector in gc apps. Luckly when allocating Core Founation objects when specifying the collector if you provide NULL, kCFAllocatorDefault or kCFAllocatorSystemDefault those all allocate memory from the garbage collection zone. In fact by default all Core Foundation Objects allocate from the garbage collection zone.

With Core Foundation any objects you allocate need to be either be released with CFRelease or CFMakeCollectable. Personally I use CFMakeCollectable as I think it makes the intent of the code more clear. Technically speaking CFRelease and CFMakeCollectable are nearly identical, if you do another CFRetain on a Core Foundation object you will need to use a CFRelease or CFMakeCollectable to balance it out. If you are writing code to run on both it'd be pretty easy to check for which one you need to do by checking to see if [NSGarbage collector defaultCollector] is NULL, otherwise CFMakeCollectable is just a no-op in a retain/release environment.
if ([NSGarbageCollector defaultCollector] == NULL) CFRelease(myCFString)


How do I turn this on in my projects?
Garbage Collection is currently only available on Mac OS X projects and not available on iOS yet. To turn on garbage collection in your application you need to open your project settings and search for garbage collection
gc_setting.png
There are 3 possible values you can have for your application.
(1) No GC Flag - Garbage Collection is not supported
(2) -fobjc-gc-only - When compiling with this set, Garbage Collection is required. If you have some bit of code in an external project that is gc only and try to use it in a project that does not support GC then you will get linker errors
(3) -fobjc-gc - When compiling with this both Garbage Collection code and traditional Retain/Release code is generated and the code can be loaded into any app. You probably will not compile apps with this setting and instead use this for Frameworks.
Typically you'll make your Apps support garbage collection or not, and your frameworks will be built with in supported mode (generating both gc and retain/release code.)


A note on Debugging GC
When using the heapshot in instruments you should set the environment variable AUTO_USE_TLC = NO because unfortunately the heapshot feature and the GC Thread Local collector don't work well together. Otherwise the heapshot feature in instruments will think you have more memory allocated than you really do. This and other GC environment variables are mentioned in the famous Mac OS X Debugging Magic Tech Note.
Instruments also contains a great instrument to show you when, for how long and how much the collector collected at various points in your application. If you are writing any gc code it would be to your advantage to run this every so often and get a feel for when the collector is running and what modes it is running in.
gc_modes.png

Conclusion

Managing memory in Objective-C is not nearly as hard as anybody would make it out to be. It's merely a matter of knowing the few memory management rules and periodically running Instruments on on your app, and the clang static analyzer in Xcode to eliminate memory issues. Garbage Collection eliminates many of the issues associated with manual objective-c retain/release, but you still have to know a few rules and how the collector works.

Releated Reading

Mac OS X Debugging Magic Tech Note
Memory Management Programming Guide
Garbage Collection Programming Guide
Instruments User Guide

Wednesday, January 20, 2010

Understanding the Objective-C Runtime

Screen shot 2010-01-15 at 10.18.04 AM.png
The Objective-C Runtime is one of the overlooked features of Objective-C initially when people are generally introduced to Cocoa/Objective-C. The reason for this is that while Objective-C (the language) is easy to pick up in only a couple hours, newcomers to Cocoa spend most of their time wrapping their heads around the Cocoa Framework and adjusting to how it works. However the runtime is something that everybody should at least know how it works in some detail beyond knowing that code like [target doMethodWith:var1]; gets translated into objc_msgSend(target,@selector(doMethodWith:),var1); by the compiler. Knowing what the Objective-C runtime is doing will help you gain a much deeper understanding of Objective-C itself and how your app is run. I think Mac/iPhone Developers will gain something from this, regardless of your level of experience.

The Objective-C Runtime is Open Source
The Objective-C Runtime is open source and available anytime from http://opensource.apple.com. In fact examining the Objective-C is one of the first ways I went through to figure out how it worked, beyond reading Apples documentation on the matter. You can download the current version of the runtime (as of this writting) for Mac OS X 10.6.2 here objc4-437.1.tar.gz.

Dynamic vs Static Languages
Objective-C is a runtime oriented language, which means that when it's possible it defers decisions about what will actually be executed from compile & link time to when it's actually executing on the runtime. This gives you a lot of flexibility in that you can redirect messages to appropriate objects as you need to or you can even intentionally swap method implementations, etc. This requires the use of a runtime which can introspect objects to see what they do & don't respond to and dispatch methods appropriately. If we contrast this to a language like C. In C you start out with a main() method and then from there it's pretty much a top down design of following your logic and executing functions as you've written your code. A C struct can't forward requests to perform a function onto other targets. Pretty much you have a program like so

#include < stdio.h >
 
int main(int argc, const char **argv[])
{
        printf("Hello World!");
        return 0;
} 
which a compiler parses, optimizes and then transforms your optimized code into assembly
.text
 .align 4,0x90
 .globl _main
_main:
Leh_func_begin1:
 pushq %rbp
Llabel1:
 movq %rsp, %rbp
Llabel2:
 subq $16, %rsp
Llabel3:
 movq %rsi, %rax
 movl %edi, %ecx
 movl %ecx, -8(%rbp)
 movq %rax, -16(%rbp)
 xorb %al, %al
 leaq LC(%rip), %rcx
 movq %rcx, %rdi
 call _printf
 movl $0, -4(%rbp)
 movl -4(%rbp), %eax
 addq $16, %rsp
 popq %rbp
 ret
Leh_func_end1:
 .cstring
LC:
 .asciz "Hello World!"
and then links it together with a library and produces a executable. This contrasts from Objective-C in that while the process is similar the code that the compiler generates depends on the presence of the Objective-C Runtime Library. When we are all initially introduced to Objective-C we are told that (at a simplistic level) what happens to our Objective-C bracket code is something like...
[self doSomethingWithVar:var1];
gets translated to...
objc_msgSend(self,@selector(doSomethingWithVar:),var1);
but beyond this we don't really know much till much later on what the runtime is doing.

What is the Objective-C Runtime?
The Objective-C Runtime is a Runtime Library, it's a library written mainly in C & Assembler that adds the Object Oriented capabilities to C to create Objective-C. This means it loads in Class information, does all method dispatching, method forwarding, etc. The Objective-C runtime essentially creates all the support structures that make Object Oriented Programming with Objective-C Possible.


Objective-C Runtime Terminology
So before we go on much further, let's get some terminology out of the way so we are all on the same page about everything. 2 Runtimes As far as Mac & iPhone Developers are concerned there are 2 runtimes: The Modern Runtime & the Legacy Runtime Modern Runtime: Covers all 64 bit Mac OS X Apps & all iPhone OS Apps Legacy Runtime: Covers everything else (all 32 bit Mac OS X Apps) Method There are 2 basic types of methods. Instance Methods (begin with a '-' like -(void)doFoo; that operate on Object Instances. And Class Methods (begin with a '+' like + (id)alloc. Methods are just like C Functions in that they are a grouping of code that performs a small task like
-(NSString *)movieTitle
{
    return @"Futurama: Into the Wild Green Yonder";
}
Selector A selector in Objective-C is essentially a C data struct that serves as a mean to identify an Objective-C method you want an object to perform. In the runtime it's defined like so...
typedef struct objc_selector  *SEL; 
and used like so...
SEL aSel = @selector(movieTitle); 
Message
[target getMovieTitleForObject:obj];
An Objective-C Message is everything between the 2 brackets '[ ]' and consists of the target you are sending a message to, the method you want it to perform and any arguments you are sending it. A Objective-C message while similar to a C function call is different. The fact that you send a message to an object doesn't mean that it'll perform it. The Object could check who the sender of the message is and based on that decide to perform a different method or forward the message onto a different target object. Class If you look in the runtime for a class you'll come across this...
typedef struct objc_class *Class;
typedef struct objc_object {
    Class isa;
} *id; 
Here there are several things going on. We have a struct for an Objective-C Class and a struct for an object. All the objc_object has is a class pointer defined as isa, this is what we mean by the term 'isa pointer'. This isa pointer is all the Objective-C Runtime needs to inspect an object and see what it's class is and then begin seeing if it responds to selectors when you are messaging objects. And lastly we see the id pointer. The id pointer by default tells us nothing about Objective-C objects except that they are Objective-C objects. When you have a id pointer you can then ask that object for it's class, see if it responds to a method, etc and then act more specifically when you know what the object is that you are pointing to. You can see this as well on Blocks in the LLVM/Clang docs
struct Block_literal_1 {
    void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
    int flags;
    int reserved; 
    void (*invoke)(void *, ...);
    struct Block_descriptor_1 {
 unsigned long int reserved; // NULL
     unsigned long int size;  // sizeof(struct Block_literal_1)
 // optional helper functions
     void (*copy_helper)(void *dst, void *src);
     void (*dispose_helper)(void *src); 
    } *descriptor;
    // imported variables
}; 
Blocks themselves are designed to be compatible with the Objective-C runtime so they are treated as objects so they can respond to messages like -retain,-release,-copy,etc. IMP (Method Implementations)
typedef id (*IMP)(id self,SEL _cmd,...); 
IMP's are function pointers to the method implementations that the compiler will generate for you. If your new to Objective-C you don't need to deal with these directly until much later on, but this is how the Objective-C runtime invokes your methods as we'll see soon. Objective-C Classes So what's in an Objectve-C Class? The basic implementation of a class in Objective-C looks like
@interface MyClass : NSObject {
//vars
NSInteger counter;
}
//methods
-(void)doFoo;
@end
but the runtime has more than that to keep track of
#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif 
We can see a class has a reference to it's superclass, it's name, instance variables, methods, cache and protocols it claims to adhere to. The runtime needs this information when responding to messages that message your class or it's instances.


So Classes define objects and yet are objects themselves? How does this work
Yes earlier I said that in objective-c classes themselves are objects as well, and the runtime deals with this by creating Meta Classes. When you send a message like [NSObject alloc] you are actually sending a message to the class object, and that class object needs to be an instance of the MetaClass which itself is an instance of the root meta class. While if you say subclass from NSObject, your class points to NSObject as it's superclass. However all meta classes point to the root metaclass as their superclass. All meta classes simply have the class methods for their method list of messages that they respond to. So when you send a message to a class object like [NSObject alloc] then objc_msgSend() actually looks through the meta class to see what it responds to then if it finds a method, operates on the Class object.

Why we subclass from Apples Classes
So initially when you start Cocoa development, tutorials all say to do things like subclass NSObject and start then coding something and you enjoy a lot of benefits simply by inheriting from Apples Classes. One thing you don't even realize that happens for you is setting your objects up to work with the Objective-C runtime. When we allocate an instance of one of our classes it's done like so...
MyObject *object = [[MyObject alloc] init];
the very first message that gets executed is +alloc. If you look at the documentation it says that "The isa instance variable of the new instance is initialized to a data structure that describes the class; memory for all other instance variables is set to 0." So by inheriting from Apples classes we not only inherit some great attributes, but we inherit the ability to easily allocate and create our objects in memory that matches a structure the runtime expects (with a isa pointer that points to our class) & is the size of our class.


So what's with the Class Cache? ( objc_cache *cache )
When the Objective-C runtime inspects an object by following it's isa pointer it can find an object that implements many methods. However you may only call a small portion of them and it makes no sense to search the classes dispatch table for all the selectors every time it does a lookup. So the class implements a cache, whenever you search through a classes dispatch table and find the corresponding selector it puts that into it's cache. So when objc_msgSend() looks through a class for a selector it searches through the class cache first. This operates on the theory that if you call a message on a class once, you are likely to call that same message on it again later. So if we take this into account this means that if we have a subclass of NSObject called MyObject and run the following code
MyObject *obj = [[MyObject alloc] init];
 
@implementation MyObject
-(id)init {
    if(self = [super init]){
        [self setVarA:@”blah”];
    }
    return self;
}
@end
the following happens (1) [MyObject alloc] gets executed first. MyObject class doesn't implement alloc so we will fail to find +alloc in the class and follow the superclass pointer which points to NSObject (2) We ask NSObject if it responds to +alloc and it does. +alloc checks the receiver class which is MyObject and allocates a block of memory the size of our class and initializes it's isa pointer to the MyObject class and we now have an instance and lastly we put +alloc in NSObject's class cache for the class object (3) Up till now we were sending a class messages but now we send an instance message which simply calls -init or our designated initializer. Of course our class responds to that message so -(id)init get's put into the cache (4) Then self = [super init] gets called. Super being a magic keyword that points to the objects superclass so we go to NSObject and call it's init method. This is done to insure that OOP Inheritance works correctly in that all your super classes will initialize their variables correctly and then you (being in the subclass) can initialize your variables correctly and then override the superclasses if you really need to. In the case of NSObject, nothing of huge importance goes on, but that is not always the case. Sometimes important initialization happens. Take this...
#import < Foundation/Foundation.h>
 
@interface MyObject : NSObject
{
 NSString *aString;
}
 
@property(retain) NSString *aString;
 
@end
 
@implementation MyObject
 
-(id)init
{
 if (self = [super init]) {
  [self setAString:nil];
 }
 return self;
}
 
@synthesize aString;
 
@end
 
 
 
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
 id obj1 = [NSMutableArray alloc];
 id obj2 = [[NSMutableArray alloc] init];
  
 id obj3 = [NSArray alloc];
 id obj4 = [[NSArray alloc] initWithObjects:@"Hello",nil];
  
 NSLog(@"obj1 class is %@",NSStringFromClass([obj1 class]));
 NSLog(@"obj2 class is %@",NSStringFromClass([obj2 class]));
  
 NSLog(@"obj3 class is %@",NSStringFromClass([obj3 class]));
 NSLog(@"obj4 class is %@",NSStringFromClass([obj4 class]));
  
 id obj5 = [MyObject alloc];
 id obj6 = [[MyObject alloc] init];
  
 NSLog(@"obj5 class is %@",NSStringFromClass([obj5 class]));
 NSLog(@"obj6 class is %@",NSStringFromClass([obj6 class]));
  
 [pool drain];
    return 0;
}
Now if you were new to Cocoa and I asked you to guess as to what would be printed you'd probably say
NSMutableArray
NSMutableArray 
NSArray
NSArray
MyObject
MyObject
but this is what happens
obj1 class is __NSPlaceholderArray
obj2 class is NSCFArray
obj3 class is __NSPlaceholderArray
obj4 class is NSCFArray
obj5 class is MyObject
obj6 class is MyObject
This is because in Objective-C there is a potential for +alloc to return an object of one class and then -init to return an object of another class.

So what happens in objc_msgSend anyway?
There is actually a lot that happens in objc_msgSend(). Lets say we have code like this...
[self printMessageWithString:@"Hello World!"];
it actually get's translated by the compiler to...
objc_msgSend(self,@selector(printMessageWithString:),@"Hello World!");
From there we follow the target objects isa pointer to lookup and see if the object (or any of it's superclasses) respond to the selector @selector(printMessageWithString:). Assuming we find the selector in the class dispatch table or it's cache we follow the function pointer and execute it. Thus objc_msgSend() never returns, it begins executing and then follows a pointer to your methods and then your methods return, thus looking like objc_msgSend() returned. Bill Bumgarner went into much more detail ( Part 1, Part 2 & Part 3) on objc_msgSend() than I will here. But to summarize what he said and what you'd see looking at the Objective-C runtime code... 1. Checks for Ignored Selectors & Short Circut - Obviously if we are running under garbage collection we can ignore calls to -retain,-release, etc 2. Check for nil target. Unlike other languages messaging nil in Objective-C is perfectly legal & there are some valid reasons you'd want to. Assuming we have a non nil target we go on... 3. Then we need to find the IMP on the class, so we first search the class cache for it, if found then follow the pointer and jump to the function 4. If the IMP isn't found in the cache then the class dispatch table is searched next, if it's found there follow the pointer and jump to the pointer 5. If the IMP isn't found in the cache or class dispatch table then we jump to the forwarding mechanism This means in the end your code is transformed by the compiler into C functions. So a method you write like say...
-(int)doComputeWithNum:(int)aNum 
would be transformed into...
int aClass_doComputeWithNum(aClass *self,SEL _cmd,int aNum) 
And the Objective-C Runtime calls your methods by invoking function pointers to those methods. Now I said that you cannot call those translated methods directly, however the Cocoa Framework does provide a method to get at the pointer...
//declare C function pointer
int (computeNum *)(id,SEL,int);
 
//methodForSelector is COCOA & not ObjC Runtime
//gets the same function pointer objc_msgSend gets
computeNum = (int (*)(id,SEL,int))[target methodForSelector:@selector(doComputeWithNum:)];
 
//execute the C function pointer returned by the runtime
computeNum(obj,@selector(doComputeWithNum:),aNum); 
In this way you can get direct access to the function and directly invoke it at runtime and even use this to circumvent the dynamism of the runtime if you absolutely need to make sure that a specific method is executed. This is the same way the Objective-C Runtime invokes your method, but using objc_msgSend().

Objective-C Message Forwarding
In Objective-C it's very legal (and may even be an intentional design decision) to send messages to objects to which they don't know how to respond to. One reason Apple gives for this in their docs is to simulate multiple inheritance which Objective-C doesn't natively support, or you may just want to abstract your design and hide another object/class behind the scenes that deals with the message. This is one thing that the runtime is very necessary for. It works like so 1. The Runtime searches through the class cache and class dispatch table of your class and all the super classes, but fails to to find the specified method 2. The Objective-C Runtime will call + (BOOL) resolveInstanceMethod:(SEL)aSEL on your class. This gives you a chance to provide a method implementation and tell the runtime that you've resolved this method and if it should begin to do it's search it'll find the method now. You could accomplish this like so... define a function...
void fooMethod(id obj, SEL _cmd)
{
 NSLog(@"Doing Foo");
}
you could then resolve it like so using class_addMethod()...
+(BOOL)resolveInstanceMethod:(SEL)aSEL
{
    if(aSEL == @selector(doFoo:)){
        class_addMethod([self class],aSEL,(IMP)fooMethod,"v@:");
        return YES;
    }
    return [super resolveInstanceMethod];
}
The "v@:" in the last part of class_addMethod() is what the method is returning and it's arguments. You can see what you can put there in the Type Encodings section of the Runtime Guide. 3. The Runtime then calls - (id)forwardingTargetForSelector:(SEL)aSelector. What this does is give you a chance (since we couldn't resolve the method (see #2 above)) to point the Objective-C runtime at another object which should respond to the message, also this is better to do before the more expensive process of invoking - (void)forwardInvocation:(NSInvocation *)anInvocation takes over. You could implement it like so
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    if(aSelector == @selector(mysteriousMethod:)){
        return alternateObject;
    }
    return [super forwardingTargetForSelector:aSelector];
}
Obviously you don't want to ever return self from this method or it could result in an infinite loop. 4. The Runtime then tries one last time to get a message sent to it's intended target and calls - (void)forwardInvocation:(NSInvocation *)anInvocation. If you've never seen NSInvocation, it's essentially an Objective-C Message in object form. Once you have an NSInvocation you essentially can change anything about the message including it's target, selector & arguments. So you could do...
-(void)forwardInvocation:(NSInvocation *)invocation
{
    SEL invSEL = invocation.selector;
 
    if([altObject respondsToSelector:invSEL]) {
        [invocation invokeWithTarget:altObject];
    } else {
        [self doesNotRecognizeSelector:invSEL];
    }
}
by default if you inherit from NSObject it's - (void)forwardInvocation:(NSInvocation *)anInvocation implementation simply calls -doesNotRecognizeSelector: which you could override if you wanted to for one last chance to do something about it.

Non Fragile ivars (Modern Runtime)
One of the things we recently gained in the modern runtime is the concept of Non Fragile ivars. When compiling your classes a ivar layout is made by the compiler that shows where to access your ivars in your classes, this is the low level detail of getting a pointer to your object, seeing where the ivar is offset in relation to the beginning of the bytes the object points at, and reading in the amount of bytes that is the size of the type of variable you are reading in. So your ivar layout may look like this, with the number in the left column being the byte offset.

  nf1.png







Here we have the ivar layout for NSObject and then we subclass NSObject to extend it and add on our own ivars. This works fine until Apple ships a update or all new Mac OS X 10.x release and this happens

nf2.png







Your custom objects get wiped out because we have an overlapping superclass. The only alternative that could prevent this is if Apple sticked with the layout it had before, but if they did that then their Frameworks could never advance because their ivar layouts were frozen in stone. Under fragile ivars you have to recompile your classes that inherit from Apples classes to restore compatibility. So what Happens under non fragile ivars?

  nf3.png









Under Non Fragile ivars the compiler generates the same ivar layout as under fragile ivars. However when the runtime detects an overlapping superclass it adjusts the offsets to your additions to the class, thus your additions in a subclass are preserved.

Objective-C Associated Objects
One thing recently introduced in Mac OS X 10.6 Snow Leopard was called Associated References. Objective-C has no support for dynamically adding on variables to objects unlike some other languages that have native support for this. So up until now you would have had to go to great lengths to build the infrastructure to pretend that you are adding a variable onto a class. Now in Mac OS X 10.6, the Objective-C Runtime has native support for this. If we wanted to add a variable to every class that already exists like say NSView we could do so like this...
#import < Cocoa/Cocoa.h> //Cocoa
#include < objc/runtime.h> //objc runtime api’s
 
@interface NSView (CustomAdditions)
@property(retain) NSImage *customImage;
@end
 
@implementation NSView (CustomAdditions)
 
static char img_key; //has a unique address (identifier)
 
-(NSImage *)customImage
{
    return objc_getAssociatedObject(self,&img_key);
}
 
-(void)setCustomImage:(NSImage *)image
{
    objc_setAssociatedObject(self,&img_key,image,
                             OBJC_ASSOCIATION_RETAIN);
}
 
@end
you can see in runtime.h the options for how to store the values passed to objc_setAssociatedObject().
/* Associated Object support. */
 
/* objc_setAssociatedObject() options */
enum {
    OBJC_ASSOCIATION_ASSIGN = 0,
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
    OBJC_ASSOCIATION_RETAIN = 01401,
    OBJC_ASSOCIATION_COPY = 01403
}; 
These match up with the options you can pass in the @property syntax.

Hybrid vTable Dispatch
If you look through the modern runtime code you'll come across this (in objc-runtime-new.m)...
/***********************************************************************
* vtable dispatch
* 
* Every class gets a vtable pointer. The vtable is an array of IMPs.
* The selectors represented in the vtable are the same for all classes
*   (i.e. no class has a bigger or smaller vtable).
* Each vtable index has an associated trampoline which dispatches to 
*   the IMP at that index for the receiver class's vtable (after 
*   checking for NULL). Dispatch fixup uses these trampolines instead 
*   of objc_msgSend.
* Fragility: The vtable size and list of selectors is chosen at launch 
*   time. No compiler-generated code depends on any particular vtable 
*   configuration, or even the use of vtable dispatch at all.
* Memory size: If a class's vtable is identical to its superclass's 
*   (i.e. the class overrides none of the vtable selectors), then 
*   the class points directly to its superclass's vtable. This means 
*   selectors to be included in the vtable should be chosen so they are 
*   (1) frequently called, but (2) not too frequently overridden. In 
*   particular, -dealloc is a bad choice.
* Forwarding: If a class doesn't implement some vtable selector, that 
*   selector's IMP is set to objc_msgSend in that class's vtable.
* +initialize: Each class keeps the default vtable (which always 
*   redirects to objc_msgSend) until its +initialize is completed.
*   Otherwise, the first message to a class could be a vtable dispatch, 
*   and the vtable trampoline doesn't include +initialize checking.
* Changes: Categories, addMethod, and setImplementation all force vtable 
*   reconstruction for the class and all of its subclasses, if the 
*   vtable selectors are affected.
**********************************************************************/
The idea behind this is that the runtime is trying to store in this vtable the most called selectors so this in turn speeds up your app because it uses fewer instructions than objc_msgSend. This vtable is the 16 most called selectors which make up an overwheling majority of all the selectors called globally, in fact further down in the code you can see the default selectors for Garbage Collected & non Garbage Collected apps...
static const char * const defaultVtable[] = {
    "allocWithZone:", 
    "alloc", 
    "class", 
    "self", 
    "isKindOfClass:", 
    "respondsToSelector:", 
    "isFlipped", 
    "length", 
    "objectForKey:", 
    "count", 
    "objectAtIndex:", 
    "isEqualToString:", 
    "isEqual:", 
    "retain", 
    "release", 
    "autorelease", 
};
static const char * const defaultVtableGC[] = {
    "allocWithZone:", 
    "alloc", 
    "class", 
    "self", 
    "isKindOfClass:", 
    "respondsToSelector:", 
    "isFlipped", 
    "length", 
    "objectForKey:", 
    "count", 
    "objectAtIndex:", 
    "isEqualToString:", 
    "isEqual:", 
    "hash", 
    "addObject:", 
    "countByEnumeratingWithState:objects:count:", 
};
So how will you know if your dealing with it? You'll see one of several methods called in your stack traces while your debugging. All of these you should basically treat just like they are objc_msgSend() for debugging purposes... objc_msgSend_fixup happens when the runtime is assigning one of these methods that your calling a slot in the vtable. objc_msgSend_fixedup occurs when your calling one of these methods that was supposed to be in the vtable but is no longer in there objc_msgSend_vtable[0-15] you'll might see a call to something like objc_msgSend_vtable5 this means you are calling one of these common methods in the vtable. The runtime can assign and unassign these as it wants to, so you shouldn't count on the fact that objc_msgSend_vtable10 corresponds to -length on one run means it'll ever be there on any of your next runs.


Conclusion
I hope you liked this, this article essentially makes up the content I covered in my Objective-C Runtime talk to the Des Moines Cocoaheads (a lot to pack in for as long a talk as we had.) The Objective-C Runtime is a great piece of work, it does a lot powering our Cocoa/Objective-C apps and makes possible so many features we just take for granted. Hope I hope if you haven't yet you'll take a look through these docs Apple has that show how you can take advantage of the Objective-C Runtime. Thanks! Objective-C Runtime Programming Guide Objective-C Runtime Reference

Sunday, January 10, 2010

Des Moines Cocoaheads 1/14: Understanding the Objective-C Runtime

http://cocoaheads.org/us/DesMoinesIowa/index.html Where: Impromptu Studios in Downtown Des Moines, IA 300 SW 5th St, Suite 220 When : Thursday, January 14 @ 7pm I will be doing a talk this Thursday at the Des Moines Cocoaheads on Understanding the Objective-C Runtime. The talk is applicable to both Mac OS X & iPhone Developers and will cover a range of beginner to advanced materials. We'll go over how the Objective-C runtime functions, how your bracket code is transformed by the compiler and what it takes to make Objective-C function the way we expect. There will be plenty of time for Q&A afterwards. If your in Central Iowa come on in and say hello to everybody! Some time after this talk is concluded, the talk will be posted here in one form or another (either i'll do a screencast or write an article from the contents of the talk, depending on what I have time for.)

Wednesday, September 16, 2009

A Guide to Blocks & Grand Central Dispatch (and the Cocoa API's making use of them)

Intro As you may or may not know I recently did a talk at the Des Moines Cocoaheads in which I reviewed Blocks and Grand Central Dispatch. I have tried to capture the content of that talk and a lot more here in this article. The talk encompassed

  • Blocks
  • Grand Central Dispatch
  • GCD Design Patterns
  • Cocoa API's using GCD and Blocks

All of the content of this article applies only to Mac OS X 10.6 Snow Leopard as blocks support and Grand Central Dispatch are only available there. There are alternate methods to get blocks onto Mac OS X 10.5 and the iPhone OS via projects like Plausible Blocks which have blocks support, though do not have Grand Central Dispatch (libdispatch.)

Grand Central Dispatch is Open Source I should mention that Apple has in fact Open Sourced libdispatch (Grand Central Dispatch) on Mac OS Forge and the other components like Kernel Support for GCD (although if implemented on other OS's this is not necessary) and the blocks runtime support are all freely available and if you want you can even checkout the libdispatch repository using Git with the command git clone git://git.macosforge.org/libdispatch.git

Blocks

Blocks are part of a new C Language Extension, and are available in C, Objective-C, C++ and Objective-C++. Right off the bat, I should say that while we will use blocks with Grand Central Dispatch a lot later on, they are not required when using Grand Central Dispatch. Blocks are very useful onto themselves even if you never use them with anything else. However we gain a lot of benefit when we use blocks with Grand Central Dispatch, so pretty much all my examples here will use blocks.

What are blocks? Well let me show you a very basic example of one

^{ NSLog(@"Inside a block"); }

This is a very basic example of a block, but it is basically a block that accepts no arguments and contains a NSLog() statement. Think of blocks as either a method or snippet of code that accepts arguments and captures lexical scope. Other languages have already had something like this concept implemented for a while (since the 70's at least if I remember correctly.) Here's a couple examples of this concept in one of my favorite languages Python

>>>f = lambda x,y,z: x + y + z
...
>>> f(2,3,4)
9

Here we are defining a lambda in Python which is basically a function that we can execute later on. In Python after the lambda keyword you define the arguments that you are passing in to the left of the colon and the right is the actual expression that will get executed. So in the first line of code we've defined a lambda that accepts 3 arguments and when it's invoked all it will do is accept the arguments and add them together, hence when we invoke f like f(2,3,4) we get 9 back. We can do more with Python lambda's. Python has functions that actually do more with lambdas like in this example...

>>>reduce((lambda x,y: x+y),[1,2,3,4])
10
>>>reduce((lambda x,y: x*y),[1,2,3,4])
24

This reduce function uses a lambda that accepts 2 arguments to iterate over an array. The lambda in this case accepts 2 arguments (as the reduce function requires) and in the first example just iterates over the array with it. Python begins by calling the lambda using the first 2 elements of the array then gets a resulting value and again calls the lambda with that resulting value and the next element in the array and keeps on calling the lambda until it has fully iterated over the data set. So in other words the function is executed like so (((1 + 2) + 3) + 4)

Blocks bring this concept to C and do a lot more. You might ask yourself "But haven't we already had this in C? I mean there are C Function Pointers." Well yeah, but while blocks are similar in concept, they do a lot more than C Function Pointers, and even better if you already know how to use C function pointers, Blocks should be fairly easy to pick up.

Here is a C Function Pointer Declaration...

 void (*func)(void); 

...and here is a Block Declaration...

 void (^block)(void); 

Both define a function that returns nothing (void) and takes no arguments. The only difference is that we've changed the name and swapped out a "*" for a "^". So lets create a basic block

 int (^MyBlock)(int) = ^(int num) { return num * 3; }; 

The block is laid out like so. The first part signifies that it's a block returning an int. The (^MyBlock)(int) is defining a block of the MyBlock type that accepts an int as an argument. Then the ^(int num) to the right of the assignment operator is the beginning of the block, it means this is a block that accepts an int as an argument (matching the declaration earlier.) Then the { return num * 3; }; is the actual body of the block that will be executed.

When we've defined the block as shown earlier we can then assign it to variables and pass it in as arguments like so...

int aNum = MyBlock(3);

printf(“Num %i”,aNum); //9 

Blocks Capturing Scope: When I said earlier that blocks capture lexical scope this is what I mean, blocks are not only useful to use as a replacement for c function pointers, but they also capture the state of any references you use within the block itself. Let me show you...

int spec = 4;
 
int (^MyBlock)(int) = ^(int aNum){
 return aNum * spec;
};

spec = 0;
printf("Block value is %d",MyBlock(4));

Here we've done a few things. First I declared an integer and assigned it a value of 4. Then we created the block and assigned it to an actual block implementation and finally called the block in a printf statement. And finally it prints out "Block value is 16"? Wait we changed the spec number to 0 just before we called it didn't we? Well yes actually we did. But what blocks do actually is create a const copy of anything you reference in the block itself that is not passed in as an argument. So in other words we can change the variable spec to anything we want after assigning the block, but unless we are passing in the variable as an argument the block will always return 16 assuming we are calling it as MyBlock(4). I should also note that we can also use C's typedef utility to make referencing this type of block easier. So in other words...

int spec = 4;
 
typedef int (^MyBlock)(int);
 
MyBlock InBlock = ^(int aNum){
 return aNum * spec;
};

spec = 0;
printf("InBlock value is %d",InBlock(4));

is exactly equivalent to the previous code example. The difference being is that the latter is more readable.

__block Blocks do have a new storage attribute that you can affix onto variables. Lets say that in the previous example we want the block to read in our spec variable by reference so that when we do change the variable spec that our call to InBlock(4) actually returns what we expect it to return which is 0. To do so all we need to change is adding __block to spec like so...

__block int spec = 4;
 
typedef int (^MyBlock)(int);
 
MyBlock InBlock = ^(int aNum){
 return aNum * spec;
};

spec = 0;
printf("InBlock value is %d",InBlock(4));

and now the printf statement finally spits out "InBlock value is 0", because now it's reading in the variable spec by reference instead of using the const copy it would otherwise use.

Blocks as Objective-C objects and more! Naturally going through this you'd almost be thinking right now that blocks are great, but they could potentially have some problems with Objective-C, not so Blocks are Objective-C objects! They do have a isa pointer and do respond to basic commands like -copy and -release which means we can use them in Objective-C dot syntax like so...

@property(copy) void(^myCallback)(id obj);
@property(readwrite,copy) MyBlock inBlock;

and in your Objective-C code you can call your blocks just like so self.inBlock();.

Finally I should note that while debugging your code there is a new GDB command specifically for calling blocks like so

$gdb invoke-block MyBlock 12 //like MyBlock(12)
$gdb invoke-block StringBlock “\” String \”” 

These give you the ability to call your blocks and pass in arguments to them during your debug sessions.

Grand Central Dispatch

Now onto Grand Central Dispatch (which I may just reference as GCD from here on out.) Unlike past additions to Mac OS X like say NSOperation/NSThread Subclasses, Grand Central Dispatch is not just a new abstraction around what we've already been using, it's an entire new underlying mechanism that makes multithreading easier and makes it easy to be as concurrent as your code can be without worrying about the variables like how much work your CPU cores are doing, how many CPU cores you have and how much threads you should spawn in response. You just use the Grand Central Dispatch API's and it handles the work of doing the appropriate amount of work. This is also not just in Cocoa, anything running on Mac OS X 10.6 Snow Leopard can take advantage of Grand Central Dispatch ( libdispatch ) because it's included in libSystem.dylib and all you need to do is include #import <dispatch/dispatch.h> in your app and you'll be able to take advantage of Grand Central Dispatch.

Grand Central Dispatch also has some other nice benefits. I've mentioned this before in other talks, but in OS design there are 2 main memory spaces (kernel space and user land.) When code you call executes a syscall and digs down into the kernel you pay a time penalty for doing so. Grand Central Dispatch will try and do it's best with some of it's API's and by pass the kernel to return to your application without digging into the kernel which means this is very fast. However if GCD needs to it can go down into the kernel and execute the equivalent system call and return back to your application.

Lastly GCD does some things that threading solutions in Leopard and earlier did not do. For example NSOperationQueue in Leopard took in NSOperation objects and created a thread, ran the NSOperation -(void)main on the thread and then killed the thread and repeated the process for each NSOperation object it ran, pretty much all we did on Leopard and earlier was creating threads, running them and then killing the threads. Grand Central Dispatch however has a pool of threads. When you call into GCD it will give you a thread that you run your code on and then when it's done it will give the thread back to GCD. Additionally queues in GCD will (when they have multiple blocks to run) just keep the same thread(s) running and run multiple blocks on the thread, which gives you a nice speed boost, and only then when it has no more work to do hand the thread back to GCD. So with GCD on Snow Leopard we are getting a nice speed boost just by using it because we are reusing resources over and over again and then we we aren't using them we just give them back to the system.

This makes GCD very nice to work with, it's very fast, efficient and light on your system. Even though GCD is fast and light however you should make sure that when you give blocks to GCD that there is enough work to do such that it's worth it to use a thread and concurrency. You can also create as many queues as you want to match however many tasks you are doing, the only constraint is the memory available on the users system.

GCD API So if we have a basic block again like this

^{ NSLog(@"Doing something"); }

then to get this running on another thread all we need to do is use dispatch_async() like so...

dispatch_async(queue,^{
 NSLog(@"Doing something");
});

so where did that queue reference come from? Well we just need to create or get a reference to a Grand Central Dispatch Queue ( dispatch_queue_t ) like this

dispatch_queue_t queue = dispatch_get_global_queue(0,0);

which just in case you've seen this code is equivalent to

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

In Grand Central dispatch the two most basic things you'll deal with are queues (dispatch_queue_t) and the API's to submit blocks to a queue such as dispatch_async() or dispatch_sync() and I'll explain the difference between the two later on. For now let's look at the GCD Queues.

The Main Queue The Main Queue in GCD is analogous to the main app thread (aka the AppKit thread.) The Main Queue cooperates with NSApplicationMain() to schedule blocks you submit to it to run on the main thread. This will be very handy to use later on, for now this is how you get a handle to the main queue

dispatch_queue_t main = dispatch_get_main_queue();

or you could just call get main queue inside of a dispatch call like so

dispatch_async(dispatch_get_main_queue(),^ {....

The Global Queues The next type of queue in GCD are the global queues. You have 3 of them of which you can submit blocks to. The only difference to them are the priority in which blocks are dequeued. GCD defines the following priorities which help you get a reference to each of the queues...

enum {
 DISPATCH_QUEUE_PRIORITY_HIGH = 2,
 DISPATCH_QUEUE_PRIORITY_DEFAULT = 0,
 DISPATCH_QUEUE_PRIORITY_LOW = -2,
};

When you call dispatch_get_global_queue() with DISPATCH_QUEUE_PRIORITY_HIGH as the first argument you've got a reference to the high global queue and so on for the default and low. As I said earlier the only difference is the order in which GCD will empty the queues. By default it will go and dequeue the high priority queue's blocks, then dequeue the default queues blocks and then the low. This priority doesn't really have anything to do with CPU time.

Private Queues Finally there are the private queues, these are your own queues that dequeue blocks serially. You can create them like so

dispatch_queue_t queue = dispatch_queue_create("com.MyApp.AppTask",NULL);

The first argument to dispatch_queue_create() is essentially a C string which represents the label for the queue. This label is important for several reasons

  • You can see it when running Debug tools on your app such as Instruments
  • If your app crashes in a private queue the label will show up on the crash report
  • As there are going to be lots of queues on 10.6 it's a good idea to differentiate them

By default when you create your private queues they actually all point to the default global queue. Yes you can point these queues to other queues to make a queue hierarchy using dispatch_set_target_queue(). The only thing Apple discourages is making an loop graph where you make a queue that points to another and another eventually winding back to pointing at the first one because that behavior is undefined. So you can create a queue and set it to the high priority queue or even any other queue like so

dispatch_queue_t queue = dispatch_queue_create("com.App.AppTask,0);
dispatch_queue_t high = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,NULL);

dispatch_set_target_queue(queue,high);

If you wanted to you could do the exact same with your own queues to create the queue hierarchies that I described earlier on.

Suspending Queues Additionally you may need to suspend queue's which you can do with dispatch_suspend(queue). This runs exactly like NSOperationQueue in that it won't suspend execution of the current block, but it will stop the queue dequeueing any more blocks. You should be aware of how you do this though, for example in the next example it's not clear at all what's actually run

dispatch_async(queue,^{ NSLog(@"First Block"); });
dispatch_async(queue,^{ NSLog(@"Second Block"); });
dispatch_async(queue,^{ NSLog(@"Third Block"); });

dispatch_suspend(queue);

In the above example it's not clear at all what has run, because it's entirely possible that any combination of blocks may have run.

Memory Management It may seem a bit odd, but even in fully Garbage Collected code you still have to call dispatch_retain() and dispatch_release() on your grand central dispatch objects, because as of right now they don't participate in garbage collection.

Recursive Decomposition Now calling dispatch_async() is okay to run code in a background thread, but we need to update that work back in the main thread, how how would one go about this? Well we can use that main queue and just dispatch_async() back to the main thread from within the first dispatch_async() call and update the UI there. Apple has referred to this as recursive decomposition, and it works like this

dispatch_queue_t queue = dispatch_queue_create(“com.app.task”,NULL)
dispatch_queue_t main = dispatch_get_main_queue();

dispatch_async(queue,^{
 CGFLoat num = [self doSomeMassiveComputation];

 dispatch_async(main,^{
  [self updateUIWithNumber:num];
 });
});

In this bit of code the computation is offloaded onto a background thread with dispatch_async() and then all we need to do is dispatch_async() back into the main queue which will schedule our block to run with the updated data that we computed in the background thread. This is generally the most preferable approach to using grand central dispatch is that it works best with this asynchronous design pattern. If you really need to use dispatch_sync() and absolutely make sure a block has run before going on for some reason, you could accomplish the same thing with this bit of code

dispatch_queue_t queue = dispatch_queue_create(“com.app.task”,NULL);

__block CGFloat num = 0;

dispatch_sync(queue,^{
 num = [self doSomeMassiveComputation];
});

[self updateUIWithNumber:num];

dispatch_sync() works just like dispatch_async() in that it takes a queue as an argument and a block to submit to the queue, but dispatch_sync() does not return until the block you've submitted to the queue has finished executing. So in other words the [self updateUIWithNumber:num]; code is guaranteed to not execute before the code in the block has finished running on another thread. dispatch_sync() will work just fine, but remember that Grand Central Dispatch works best with asynchronous design patterns like the first bit of code where we simply dispatch_async() back to the main queue to update the user interface as appropriate.

dispatch_apply() dispatch_async() and dispatch_sync() are all okay for dispatching bits of code one at a time, but if you need to dispatch many blocks at once this is inefficient. You could use a for loop to dispatch many blocks, but luckly GCD has a built in function for doing this and automatically waiting till the blocks all have executed. dispatch_apply() is really aimed at going through an array of items and then continuing execution of code after all the blocks have executed, like so

dispatch_queue_t queue = dispatch_get_global_queue(0,0);

dispatch_apply(queue, count, ^(size_t idx){
 do_something_with_data(data,idx);
});

//do something with data 

This is GCD's way of going through arrays, you'll see later on that Apple has added Cocoa API's for accomplishing this with NSArrays's, NSSets,etc. dispatch_apply() will take your block and iterate over the array as concurrently as it can. I've run it sometimes where it takes the indexes 0,2,4,6,8 on Core 1 and 1,3,5,7,9 on Core 2 and sometimes it's done odd patterns where it does most of the items on 1 and some on core 2, the point being that you don't know how concurrent it will be, but you do know GCD will iterate over your array or dispatch all the blocks within the max count you give it as concurrently as it can and then once it's done you just go on and work with your updated data.

Dispatch Groups Dispatch Groups were created to group several blocks together and then dispatch another block upon all the blocks in the group completing their execution. Groups are setup very easily and the syntax isn't very dissimilar from dispatch_async(). The API dispatch_group_notify() is what sets the final block to be executed upon all the other blocks finishing their execution.

dispatch_queue_t queue = dispatch_get_global_queue(0,0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group,queue,^{
 NSLog(@"Block 1");
});

dispatch_group_async(group,queue,^{
 NSLog(@"Block 2");
});

dispatch_group_notify(group,queue,^{
 NSLog(@"Final block is executed last after 1 and 2");
});

Other GCD API you may be Interested in

//Make sure GCD Dispatches a block only 1 time
dispatch_once()

//Dispatch a Block after a period of time
dispatch_after()

//Print Debugging Information
dispatch_debug()

//Create a new dispatch source to monitor low-level System objects
//and automatically submit a handler block to a dispatch queue in response to events.
dispatch_source_create() 

Cocoa & Grand Central Dispatch/Blocks

The GCD API's for being low level API's are very easy to write and quite frankly I love them and have no problem using them, but they are not appropriate for all situations. Apple has implemented many new API's in Mac OS X 10.6 Snow Leopard that take advantage of Blocks and Grand Central Dispatch such that you can work with existing classes easier & faster and when possible concurrently.

NSOperation and NSBlockOperation NSOperation has been entirely rewritten on top of GCD to take advantage of it and provide some new functionality. In Leopard when you used NSOperation(Queue) it created and killed a thread for every NSOperation object, in Mac OS X 10.6 now it uses GCD and will reuse threads to give you a nice performance boost. Additionally Apple has added a new NSOperation subclass called NSBlockOperation to which you can add a block and add multiple blocks. Apple has additionally added a completion block method to NSOperation where you can specify a block to be executed upon a NSOperation object completing (goodbye KVO for many NSOperation Objects.)

NSBlockOperation can be a nice easy way to use everything that NSOperation offers and still use blocks with NSOperation.

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
 NSLog(@"Doing something...");
}];

//you can add more blocks
[operation addExecutionBlock:^{
 NSLog(@"Another block");
}];

[operation setCompletionBlock:^{
 NSLog(@"Doing something once the operation has finished...");
}];

[queue addOperation:operation];

in this way it starts to make the NSBlockOperation look exactly like high level dispatch groups in that you can add multiple blocks and set a completion block to be executed.

Concurrent Enumeration Methods

One of the biggest implications of Blocks and Grand Central Dispatch is adding support for them throughout the Cocoa API's to make working with Cocoa/Objective-C easier and faster. Here are a couple of examples of enumerating over a NSDictionary using just a block and enumerating over a block concurrently.

//non concurrent dictionary enumeration with a block
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
  NSLog(@"Enumerating Key %@ and Value %@",key,obj);
 }];

//concurrent dictionary enumeration with a block
[dict enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent
    usingBlock:^(id key, id obj, BOOL *stop) {
     NSLog(@"Enumerating Key %@ and Value %@",key,obj);
    }];

The Documentation is a little dry on what happens here saying just "Applies a given block object to the entries of the receiver." What it doesn't make mention of is that because it has a block reference it can do this concurrently and GCD will take care of all the details of how it accomplishes this concurrency for you. You could also use the BOOL *stop pointer and search for objects inside NSDictionary and just set *stop = YES; to stop any further enumeration inside the block once you've found the key you are looking for.

High Level Cocoa API's vs Low Level GCD API's

Chris Hanson earlier wrote about why you should use NSOperation vs GCD API's. He does make some good points, however I will say that I haven't actually used NSOperation yet on Mac OS X 10.6 (although I definitely will be using it later on in the development of my app) because the Grand Central Dispatch API's are very easy to use and read and I really enjoy using them. Although he wants you to use NSOperation, I would say use what you like and is appropriate to the situation. I would say one reason I really haven't used NSOperation is because when GCD was introduced at WWDC, I heard over and over about the GCD API, and I saw how great it was and I can't really remember NSOperation or NSBlockOperation being talked about much.

To Chris's credit he does make good points about NSOperation handling dependencies better and you can use KVO if you need to use it with NSOperation Objects. Just about all the things you can do with the basic GCD API's you can accomplish with NSOperation(Queue) with the same or a minimal couple lines of more code to get the same effect. There are also several Cocoa API that are specifically meant to be used with NSOperationQueue's, so in those cases you really have no choice but to use NSOperationQueue anyway.

Overall I'd say think what you'll need to do and why you would need GCD or NSOperation(Queue) and pick appropriately. If you need to you can always write NSBlockOperation objects and then at some point later on convert those blocks to using the GCD API with a minimal amount of effort.

Further Reading on Grand Central Dispatch/Blocks

Because I only have so much time to write here, and have to split my time between work and multiple projects, I am linking to people I like who have written some great information about Grand Central Dispatch and/or Blocks. Although this article will most definitely not be my last on Grand Central Dispatch and/or Blocks.

http://www.friday.com/bbum/2009/08/29/basic-blocks/ http://www.friday.com/bbum/2009/08/29/blocks-tips-tricks/ http://www.mikeash.com/?page=pyblog/friday-qa-2009-08-28-intro-to-grand-central-dispatch-part-i-basics-and-dispatch-queues.html http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-04-intro-to-grand-central-dispatch-part-ii-multi-core-performance.html http://www.mikeash.com/?page=pyblog/friday-qa-2009-09-11-intro-to-grand-central-dispatch-part-iii-dispatch-sources.html

A couple projects making nice use of Blocks

http://github.com/amazingsyco/sscore Andy Matauschak's KVO with Blocks http://gist.github.com/153676

Interesting Cocoa API's Making Use of Blocks

A list of some of the Cocoa API's that make use of blocks (thanks to a certain someone for doing this, really appreciate it.) I should note that Apple has tried not to use the word block everywhere in it's API for a very good reason. When you come to a new API and you saw something like -[NSArray block] you would probably think it had something to do with blocking using the NSArray or something where you are blocking execution. Although many API do have block in their name, it is by no means the only keyword you should use when looking for API's dealing with blocks, for these links to work you must have the Documentation installed on your HD.

NSEvent

addGlobalMonitorForEventsMatchingMask:handler:

addLocalMonitorForEventsMatchingMask:handler:

NSSavePanel

beginSheetModalForWindow:completionHandler:

beginWithCompletionHandler:

NSWorkspace

duplicateURLs:completionHandler:

recycleURLs:completionHandler:

NSUserInterfaceItemSearching Protocol

searchForItemsWithSearchString:resultLimit: matchedItemHandler:

NSArray

enumerateObjectsAtIndexes:options:usingBlock:

enumerateObjectsUsingBlock:

enumerateObjectsWithOptions:usingBlock:

indexesOfObjectsAtIndexes:options:passingTest:

indexesOfObjectsPassingTest:

indexesOfObjectsWithOptions:passingTest:

indexOfObjectAtIndexes:options:passingTest:

indexOfObjectAtIndexes:options:passingTest:

indexOfObjectPassingTest:

indexOfObjectWithOptions:passingTest:

indexOfObjectWithOptions:passingTest:

NSAttributedString

enumerateAttribute:inRange:options:usingBlock:

enumerateAttributesInRange:options:usingBlock:

NSBlockOperation

blockOperationWithBlock:

addExecutionBlock:

executionBlocks

NSDictionary

enumerateKeysAndObjectsUsingBlock:

enumerateKeysAndObjectsWithOptions:usingBlock:

keysOfEntriesPassingTest:

keysOfEntriesWithOptions:passingTest:

NSExpression

expressionForBlock:arguments:

expressionBlock

NSFileManager

enumeratorAtURL:includingPropertiesForKeys: options:errorHandler:

NSIndexSet

enumerateIndexesInRange:options:usingBlock:

enumerateIndexesUsingBlock:

enumerateIndexesWithOptions:usingBlock:

indexesInRange:options:passingTest:

indexesPassingTest:

indexesWithOptions:passingTest:

indexInRange:options:passingTest:

indexPassingTest:

indexWithOptions:passingTest:

NSNotificationCenter

addObserverForName:object:queue:usingBlock:

NSOperation

completionBlock

setCompletionBlock:

NSOperationQueue

addOperationWithBlock:

NSPredicate

predicateWithBlock:

NSSet

enumerateObjectsUsingBlock:

enumerateObjectsWithOptions:usingBlock:

objectsPassingTest:

objectsWithOptions:passingTest:

NSString

enumerateLinesUsingBlock:

enumerateSubstringsInRange:options:usingBlock:

CATransaction

completionBlock

 
...