Don't Retain That Class!

Let's take a look at a rather unsuspecting method.

- (void)setClass:(Class):class
          forKey:(NSString *)key;

There isn't much special about it. Most likely it belongs to some object that plays some dictionary-like role, but that doesn't really matter. What does is that I would have a hard time sleeping at night if I wrote that.

I'm a pedant. Let's sprinkle it with some magic pedant pixy dust and see what happens.

- (void)setClass:(Class __unsafe_unretained):class
          forKey:(NSString *)key;

Ah, so much better. I'll sleep well tonight, or at least the pedant within.

Class Singeltons

In Objective-C classes are objects and more so, they are global singletons. Every instance of NSString will return the same object when you call the -class method, the NSString class object. Getting ahold of these singletons are quite easy. You can send the +class method to the class or use objc_getClass from the runtime.

Class a = [NSString class];

#import <objc/runtime.h>
Class b = objc_getClass("NSString");

These both return the same object. Life is great.

Retaining a Class

Let's give it a try!

NSArray *array = @[ [NSString class] ];

This code executes without a hitch. NSArray retains all object in it and thus we have successfully retained a class object. I would normally just call -retain on it but hey, MRR is dead to me.

Here's another common pattern:

@interface MonkeyObject : NSObject
@property (nonatomic, strong) Class class;
@end

Obviously assigning any class to the property will retain it since it is qualified with strong ownership. But is it safe?

It Isn't Safe

Any code that retains or releases a class can be unsafe depending on the actual class that is passed to it at run-time! Think for a moment, where does the class get the retain method in the first place?

NSLog(@"%@", [[NSString class] isKindOfClass:[NSObject class]] ? @"Yes" : @"No");

This prints "YES". The NSString class object is a subclass of NSObject. It is a subclass of its root class. That is where the -retain and -release methods come from (although it overrides them to no-op).

Let's make a class of our own.

NS_ROOT_CLASS
@interface AbsolutelyNothing
@end

Not to spoil the fun, but you can't retain the first one! It doesn't have the retain method, obviously. Let's try to put it in an array.

NSArray *array = @[ objc_getClass("AbsolutelyNothing") ];

We have to use objc_getClass because AbsolutelyNothing clearly doesn't implement the -class method, heh.

2014-03-14 10:20:58.436 Untitled[54459:507] *** NSForwarding: warning: object 0x10ce0f1c0 of class 'AbsolutelyNothing' does not implement methodSignatureForSelector: -- trouble ahead
2014-03-14 10:20:58.436 Untitled[54459:507] *** NSForwarding: warning: object 0x10ce0f1c0 of class 'AbsolutelyNothing' does not implement doesNotRecognizeSelector: -- abort
Run Command: line 1: 54459 Trace/BPT trap: 5       ./"$2" "${@:3}"

That's some mighty ugly vomit. Apparently we tried to send it a method it doesn't implement. Well duh, it doesn't implement any methods. If we want to invoke a selector on a class that it doesn't implement then the minimum we must do is implement methodSignatureForSelector: (due to the implementation of the forwarding path). Let's implement that just to see what it is trying to invoke.

NS_ROOT_CLASS
@interface AbsolutelyNothing
@end

@implementation AbsolutelyNothing
- (void)methodSignatureForSelector:(SEL):aSelector
{
  NSLog(@"Don't tell me to %@!", NSStringFromSelector(aSelector));
}
@end

...

NSArray *array = @[ objc_getClass("AbsolutelyNothing") ];

And when we run it...

2014-03-14 10:21:59.368 Untitled[54459:507] Don't tell me to retain!

See, I told you not to!

Unsafe-Unretain that Class!

Excellent grammar, right? :-P

All classes should be marked as unsafe-unretain when used as properties or passed as arguments to functions or selectors, otherwise you are going to have a bad time. Luckily you don't really have to worry about it. Clang has an exception for class objects that states

"As a special case, if the object’s base type is Class (possibly protocol-qualified), the type is adjusted to have __unsafe_unretained qualification instead."

Yay, Clang saves the day! Unfortunately this provision only exists when the type is Class. If there is no qualification whatsoever, the infamous id, then you are playing with fire since anyone could try to retain it.

The real issue here is that root classes that don't conform to the NSObject protocol are a real danger. Inserting an id into an array is only safe it if is id<NSObject>. Basically every method that takes an object really expects conformance to that protocol. Custom root classes are kind of nasty!

But why on Earth are you making root classes or using objects that don't implement -retain and -release? Stop it, or at least make it conform to the NSObject protocol.

Ah, the world is safe again.

Hmmm, What's that Selector?

The journey of a selector that is unrecognized.

Introduction

The atomic unit in Objective-C is an invocation, sending a selector to an object with some arguments. To invoke the selector doThings: on anObject we write the familiar line.

[anObject doThings:things];

Usually this calls into the method and all is well. But what happens when anObject doesn't have a method implementation for doThings?

An adventure begins where we'll meet the forwarding path, proxy objects, zombies, and some magic that is arguably witchcraft.

Buckle up; here we go. First stop, invocations!

Selector-Invocation

Objc-Message-Send, the Invoker Behind the Curtain

Invocations in Objective-C are compiled into a call to the C function objc_msgSend.

[anObject doThings:things];

// Compiled as:
objc_msgSend(anObject, @selector(doThings:), things);

objc_msgSend simply finds the imp and calls it. In this case the imp, short for implementation, is the function pointer corresponding to @selector(doThings:) in the method table for the class of anObject.

id objc_msgSend(id self, SEL _cmd, ...) {
  Class class = object_getClass(self);
  IMP imp = class_getMethodImplementation(class, _cmd);
  return imp ? imp(self, _cmd, ...) : 0;
}

objc_msgSend is actually written in assembly in order to properly handle any or no return type as well as properly load all arguments before calling the imp.

Class-Get-Method-Implementation, the Function Finder

The implementation of class_getMethodImplementation is quite simple. It calls lookupMethod which searches for the given selector in the method table of the class. If no method is found then it walks up the inheritance hierarchy looking for it. Each class owns its imp-cache and there is a path for resolving methods, a form of dynamic creation for instance and class methods, but don't let that make you think that method-lookup is complicated. It's just a linear search of an array of methods or binary search when they are sorted and then a walk up the hierarchy.

Runtime Forwarding

Objc-Message-Forward

What's interesting about the pseudo-implementation about is that  when all the caches and method lists fall through. in class_getMethodImplementation In that case it returns _objc_msgForward_internal which is then translated into a pointer to the function _objc_msgForward.  Thus when there is no method for a given selector objc_msgSend will end up calling objc_msgForward.

It and its partner in crime _objc_msgForward_stret (for methods with a struct return) are public and declared in <objc/message.h> but you have no reason to call them directly, so stop thinking about it.

If you are absolutely insane interested you can read the implementation of _objc_msgForward.

It is implemented separately for arm, i386x86-64, and a simulator-specific i386 version as well. Be warned, they are all written in assembly and quite dense!

Forwarding Handlers

The two forwarding methods described just call into the two forwarding handlers that have been specified at runtime using objc_setForwardHandler.

// <objc/runtime.h>
void objc_setForwardHandler(void *fwd, void *fwd_stret);

You are unlikely to ever set any forwarding handlers yourself but guess who does... Core Foundation!

Core Foundation's Forwarding Path

Preparation

When Core Foundation is first loaded by dyld its runs __CFInitialize as a static initializer in which it sets __forwarding_prep_0__ as the srandard forwarding handler and the nearly identical __forwarding_prep_1__ for the struct return (stret) variant. What's interesting is that the setting for the forwarding handlers, a call to objc_setForwardHandler, is missing from the CF source, yet the call is clearly visible if the framework is disassembled. There be gremlins!

Preamble

Both of the __forwarding_prep_X__ functions just call __forwarding__ function with two arguments. The first is a boolean denoting whether the return type is a struct or not. A zero is passed for __forwarding_prep_0__ and a one for __forwarding_prep_1__; at this point their names should be obvious. The second argument is the current stack pointer which is used to find the arguments that were passed to objc_msgSend, the first two of which are always self and _cmd which make for easy retrieval at the start of the method.

void __forwarding__(BOOL isStret, void *frameStackPointer, ...) {
  id receiver = *(id *)frameStackPointer;
  SEL sel = *(SEL *)(frameStackPointer + 4);

  ...
}

For brevity's sake the rest of the discussion will act as if receiver and sel are actually arguments to __forwarding__, but let the pedants sleep well knowing that I have addressed the fact that in reality they are not.

The Forwarding Path

The Setting

Let's recall our starting point. A selector is invoked on an object that does not "recognize" it and then the run-time calls the __forwarding__ function for the chance for salvation. Clearly it doesn't just crash or we would be in brutally brittle world where the simplest mistake would bring down an application and where this post would have been better served to the bit-bucket.

Let's dive down this quirky rabbit hole and see where we end up. It's time to move forward.

Forwarding Target, the Replacement Receiver

So here we are in the middle of objc_msgSend and we've hit a wall. We've got the

  • who - receiver, 
  • the what - selector,
  • and the with - arguments

but we can't quite make it happen. The easiest and fastest resolution would be to replace the receiver and then invoke the same selector with the same arguments. If there were such a replacement receiver then all that would need to happen would be to undo the call (unwind the stack and return the registers to as they were at the start of the stack frame), replace the first argument (a single stack- or register-write), and then call objc_msgSend again. It's such a quick and clean recovery!

The run-time offers the chance to return a replacement receiver, called the forwarding target, by calling the obviously named forwardingTargetForSelector: on the original receiver. If it doesn't return nil then the runtime invokes the selector on the returned object, the forwarding path is complete, and with a swift recovery life goes on.

void __forwarding__(BOOL isStret, id receiver, SEL sel, ...) {
  id forwardingTarget = [receiver forwardingTargetForSelector:sel];
  if (forwardingTarget) {
    return objc_msgSend(forwardingTarget, sel, ...);
  }

  ...
}

Note that if for some reason the selector is not recognized by the forwarding target then the forwarding path would start all over again but with the new receiver. If this actually happens then you are likely doing something wrong. Why on Earth would you tell the runtime to call the selector on an object that doesn't it? Don't be so cruel. Go play with fire instead.

Method Signature, the Frame-Forge

When forwardingTargetForSelector: does return nil the forwarding path fills into the slow branch. Here it will box up everything about the current invocation and hand it to you to do whatever with you please.

Here lies an interesting question: how, in the middle of an invocation, is it able to package up the target, selector, and all arguments, when they could easily be scattered throughout the registers or the stack (the exact details of which depend on calling conventions of the given architecture and compiler).

Grabbing all the arguments is simply not possible with a selector alone. The class does not implement the selector and thus the method signature, which includes all of type information, of the invocation is unknown. If we had the method signature for the given selector it would be possible to determine exactly where all of the arguments are and then wrap them up into an NSInvocation. It attempts to ascertain the signature by calling the aptly named methodSignatureForSelector: on the receiver.

void __forwarding__(BOOL isStret, id receiver, SEL sel, ...) {
  id forwardingTarget = [receiver forwardingTargetForSelector:sel];
  if (forwardingTarget) {
    return objc_msgSend(forwardingTarget, sel, ...);
  }

  NSMethodSignature *methodSignature = [receiver methodSignatureForSelector:sel];
  ...
}

Forward Invocation, the Everything; the End

If the receiver is able to construct and return method signature for the given selector then the last stop in the forwarding path is forwardInvocation: which is called with an NSInvocation made by scraping the stack and registers using that signature.

In forwardInvocation: you can do anything that you want including logging the invocation, changing any of the arguments or the receiver before invoking, forwarding it onto other objects (multiplexing), or simply setting the invocation's return value directly.

You should note that even if you do nothing with the invocation, its return value (defaulting to nil, Nil, NULL, 0, 0.0, the abyss, etc.) will still be loaded as the return value of the invocation and it will look as if objc_msgSend returned it.

You didn't forget that we're in the middle of objc_msgSend, did you?

void __forwarding__(BOOL isStret, id receiver, SEL sel, ...) {
  id forwardingTarget = [receiver forwardingTargetForSelector:sel];
  if (forwardingTarget) {
    return objc_msgSend(forwardingTarget, sel, ...);
  }

  NSMethodSignature *methodSignature = [receiver methodSignatureForSelector:sel];
  if (methodSignature) {
    NSInvocation *invocation = [NSInvocation _invocationWithMethodSignature:methodSignature ...];
    [receiver forwardInvocation:invocation];

    void *returnValue = NULL;
    [invocation getReturnValue:&value];
    return returnValue;
  }
  ...
}

Does Not Recognize Selector, the Gauche Goodbye

The slow path, forwardInvocation:, is dependent on the ability to return a method signature for the given selector. If nil is returned then all hopes are lost and runtime calls doesNotRecognizeSelector: and then terminates the process, literally calling kill(getpid(), 9).

In doesNotRecognizerSelector: you can do whatever you want, but realize that it is the final stop. Unfortunately all you have is the selector and it's hard to do much with it alone. If you wanted any more information then you should have returned a method signature, silly!

Usually you won't implement doesNotRecognizeSelector: and so you'll be getting NSObject's implementation which just logs an error message that you definitely seen before

-[__NSCFNumber objectAtIndex:]: unrecognized selector sent to instance 0x8a48b70

and then it throws an NSInvalidArgumentException that you can catch if you so like. Be aware that if for any reason you override doesNotRespondToSelector: yourself then you *must* throw for the chance of being caught, lest you suffer the imminent process-kill just around the corner.

void __forwarding__(BOOL isStret, id receiver, SEL sel, ...) {
  id forwardingTarget = [receiver forwardingTargetForSelector:sel];
  if (forwardingTarget) {
    return objc_msgSend(forwardingTarget, sel, ...);
  }

  NSMethodSignature *methodSignature = [receiver methodSignatureForSelector:sel];
  if (methodSignature) {
    NSInvocation *invocation = [NSInvocation _invocationWithMethodSignature:methodSignature ...];
    [receiver forwardInvocation:invocation];

    void *returnValue = NULL;
    [invocation getReturnValue:&value];
    return returnValue;
  }

  // doesNotRecognizeSelector: should throw to avoid the SIGKILL.
  [receiver doesNotRecognizeSelector:sel];
  kill(getpid(), 9);
}

The basic skeleton of the forwarding path has emerged. This still has some details missing but read on the know more!

Proxy Objects

The forwarding path has two routes: a fast one that simply allows a different target and a slow one that allows you to do anything at all with the invocation. These two combine to give the power to implement proxies in Objective-C.

proxy is an object that provides an interface to something. That might sound like the most vague definition that you have ever heard, and it is. But one way to to think about them is that they bridge the interface from one object to another.

Let's look at some examples.

Wrapper/Forwarding Proxies

Here's an incredibly contrived example of a class that wraps a scroll-view delegate. It logs in scrollViewDidScroll: and forwards all methods to the wrapped delegate. This could be implemented by overriding every scroll-view delegate method but that is not future-safe and a pain to maintain. This example is simple but should illustrate the power of a forwarding target.

@interface ScrollLoggingScrollViewDelegate : NSObject <UIScrollViewDelegate>
- (instancetype)initWithScrollViewinnerDelegate:(id<UIScrollViewDelegate>)innerDelegate;
@end

@implementation ScrollLoggingScrollViewDelegate
- (instancetype)initWithScrollViewinnerDelegate:(id<UIScrollViewDelegate>)innerDelegate {...}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
  NSLog(@"%@ is scrolling!", scrollView);
  if ([_innerDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
    [_innerDelegate scrollViewDidScroll:scrollView];
  }
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{
  if ([_innerDelegate respondsToSelector:aSelector]) {
    return _innerDelegate;
  }
  return nil;
}
@end

By the very nature of forwardingTargetForSelector: returning an alternate receiver all proxies built using it will wrap one or many objects. To unlock the full potential of proxies one must enter the land of forwarded invocations.

Full-Fledged Proxies

With invocation forwarding it is possible to implementer a multiplexer, which is an object that forwards methods to a set of objects. Here is an example of a class that will forward any method it receives to every object in the collection it was init'd with.

@interface FastEnumerationMultiplexer : NSObject
- (instancetype)initWithEnumerator:(id<NSFastEnumeration>)enumerator;
@end

@implementation FastEnumerationMultiplexer
- (instancetype)initWithEnumerator:(id<NSFastEnumeration>)enumerator {...}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
  for (id object in _enumerator) {
    // We have to use fast enumeration to get the first one.
    // There is no "anyObject" or "objectAtIndex" in NSFastEnumeration.
    return [object methodSignatureForSelector:aSelector];
  }
  return nil;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
  for (id object in _enumerator) {
    [anInvocation invokeWithTarget:object];
  }
}
@end

Then some real magic occurs when a category is added to any class supporting fast enumeration to return an instance of the multiplexer.

@interface NSArray (EnumerationMultiplexing)
- (id)do;
@end

@implementation NSArray (EnumerationMultiplexing)
- (id)do
{
  return [[FastEnumerationMultiplexer alloc] initWithEnumerator:self];
}
@end

This makes it easy to send a method to every object in the collection.

NSArray *array = @[ foo, bar, baz ];
[[array do] dumpCaches];

In just one line we managed to tell all of the objects in the array to dump their caches. Notice that this might get wonky if any object in the array doesn't implement the selector (it'll enter the forwarding path!) or if the selector has a return type (the last one's return type will be the winner) but there are details left to you to make this more robust.

Returning an object that consumes selectors/invocations is an instance higher order messaging, since here it is as if one selector is taking another as an argument. This use of proxies is also explained by Mike Ash in his post on forwarding and is used to implement mocks in a number of test frameworks including OCMock and OCMockito. In the case of mocks forwardInvocation: is used to catch and record all invocations so that expected calls can be verified and unexpected calls can issue an error.

There are many other uses of proxies and you should feel free to explore them and have fun. Adventure is out there!

NSProxy

NSProxy, is one of the few root classes available in iOS and Mac OS X, unless you make your own. It is very similar to NSObject, and even conforms to the NSObject protocol, except that it has less methods, a lot less methods. It even doesn't have an init method! If you subclass it and do create an init method then you don't have to call super! #mindblown

The reduction of methods simplifies the interface and leaves the minimal set needed to proxy the invocations it receives. Yet strangely enough, NSProxy does *not* have forwardingTargetForSelector: but only forwardInvocation: (and obviously methodSignatureForSelector: too). The idea is that forwarding targets are typically found on objects that forward some methods but have a life of their own as well.

Thus if you have some non-proxy methods you are something real, an NSObject. If you semantically an interface with some business logic then you can be an NSProxy and all forwarding takes place in the slow, more robust forwarding path. 

Are Proxies Safe?

After poking around in the bowels of objc_msgSend we've uncovered the forwarding path and from it seen how to build proxies which are quite natural constructions and allow implementing some pretty awesome patterns. There is one thing to beware though, they can be used in a way that is completely unsafe. But you'll be fine as long as you follow one rule:

Never use a proxy to masquerade as an instance of a specific class.

This says that, for example, that you should never have a proxy that claims to be an NSArray when it is actually an NSProxy or some other subclass of NSObject. This means that proxy objects should only be stored as an id type, often qualified with protocols, and as a particular class pointer.

This rule does not necessarily mean to never do it but that if you do, your proxies might be used unsafely. Here's an example proxy that can pretend to be anything.

@interface FakeObject : NSObject
@property (nonatomic, strong) id object;
@end

@implementation FakeObject
- (id)forwardingTargetForSelector:(SEL)aSelector
{
  return _object;
}
@end

And here an example of it being used to masquerade as a UIView.

UIView *proxiedView = [[UIView alloc] initWithFrame:CGRectMake(1.0, 4.0, 9.0, 16.0)];
FakeObject *proxy = [FakeObject new];
proxy.object = proxiedView;
UIView *view = (UIView *)proxy;

NSLog(@"%@", NSStringFromCGRect(view.frame));
NSLog(@"%@", view.layer);

This actually works exactly as you'd expect. Even though this is unsafe it work a lot of the time. The issue is that you never know when it won't...

UIView *parentView = [UIView new];
[parentView addSubview:view];

Sample[98633:70b] -[UIView superlayer]: unrecognized selector sent to instance 0x9073640 Sample[98633:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView superlayer]: unrecognized selector sent to instance 0x9073640' *** First throw call stack: ( 0 CoreFoundation 0x017e57e4 __exceptionPreprocess + 180 1 libobjc.A.dylib 0x015658e5 objc_exception_throw + 44 2 CoreFoundation 0x01882843 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275 3 CoreFoundation 0x017d5b0b ___forwarding___ + 1019 4 CoreFoundation 0x017d56ee _CF_forwarding_prep_0 + 14 5 UIKit 0x002987ea -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1097 6 UIKit 0x0028bada -[UIView(Hierarchy) addSubview:] + 56 7 Zoof 0x00002c3f main + 639 8 libdyld.dylib 0x01dca70d start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException

Adding the view as a subview is apparently not safe. Darn.

What's happening is that addSubview: ends up calling _addSubview:position:relativeTo: in which an ivar is accessed directly off the first argument. That is what causes the kaboom. Let's look at another example to see the issue in more detail.

Ivars and Proxies Do Not Mix

@interface Stringish : NSObject
@property (nonatomic, copy) NSString *string;
@end

@implementation Stringish
- (BOOL)isEqual:(Stringish *)object
{
  return [_string isEqualToString:object->_string];
}

- (NSInteger)hash
{
  return [_string hash];
}
@end

Passing a proxy in for the object parameter in the isEqual: method will cause the program to crash because the implementations reads an ivar right off of it. You can't forward/proxy ivar-lookup. It will try to poke right into the object's innards as if it were what it claimed to be.
Here's how the isEqual: method is going to be compiled. 

- (BOOL)isEqual:(Stringish *)object
{
  Ivar ivar = class_getInstanceVariable([Stringish class], "_string");
  ptrdiff_t offset = ivar_getOffset(ivar);

  NSString *selfString = *(id __strong *)((__bridge void *)self + offset);
  NSString *objectString = *(id __strong *)((__bridge void *)object + offset);

  return [selfString isEqualToString:objectString];
}

If object is actually a proxy then it will obviously why it crashes. There simply is no ivar at that location or if there is, it will be some ivar of the proxy object itself and still be wrong.
The previous example suffered the same fate. The addSubview: call ends up trying to pull out the layer instance variable but it reaches into the proxy and finds the proxied view instead. Total bummer.

Runtime Functions and Proxies Do Not Mix

The proxying and forwarding all discussed so far occurs through objc_msgSend, the invocation of selectors. Any functions that try to tap into the object directly will not work! You can implement class on the proxy to "pretend" that it is some other class but you won't find a way to fool object_getClass.

Similarly if you use class_getMethodImplementation to get an IMP for an object of class Foo and then call the IMP directly on a proxy-to-Foo you are going to have a bad time.

Proxy Interfaces not Implementations

The lessons and the rule above paint a very clear picture. Don't proxy over specific implementations, classes, but instead proxy only over protocols. If you do then you will always be safe. This is similar to "program to an interface not an implementation" in the exact way that doing the latter inadvertently couples the code to unexpected and uncontrollable implementation details.

The one place this rule is easily broken is in tests where you can handle the lack of safety and account for it the few times that it rears its ugly head. However this is something you definitely don't want to risk in product code or the application with die a bitter death when it hits rare/untested code-paths or Apple releases a new OS X that changes an implementation. The latter is unavoidable; don't risk it.

An Implicit Protocol For Everyone

After looking at the forwarding path we find that Core Foundation injects a few subtle assumption into the world. All classes must implement some subset of the forwarding path or madness ensues (the exact madness is revealed in the final showing of the forwarding path). We have seen that forwarding explicitly deals with four methods.

  • forwardingTargetForSelector:
  • methodSignatureForSelector:
  • forwardInvocation:
  • doesNotRecognizerSelector:

It also can indirectly call resolveClassMethod: and resolveInstanceMethod: but those aren't quite the same.

At this point in history, Objective-C and Cocoa have become more and more intertwined over the years (through NSObject, ARC, forwarding, and a few others). It is curious to wonder which of those methods, if any, are essentially required to be implemented by every object that enters the runtime.

forwardingTargetForSelector: is clearly optional. forwardInvocation: doesn't get called if a nil method signature, but then doesNotRecognizeSelector: does.

The execution paths and branch structure of the forwarding path insists that every class is expected to implemented at least methodSignatureForSelector: or the runtime will bark loudly the moment that an unrecognized selector is invoked. The error message logged when this critical method is missing is impossible to misinterpret.

*** NSForwarding: warning: object 0xadd9e58 of class XYZ does not implement methodSignatureForSelector: -- did you forget to declare the superclass of 'XYZ'?

Thus there is a secret and implicit prototol that every object conforms to.

@protocol UnrecognizedSelectorSafelyReceiving
@required
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;

@optional
- (void)doesNotRecognizeSelector:(SEL)aSelector;

// Super optional. Only needed if methodSignatureForSelector: ever returns non-nil.
- (void)forwardInvocation:(NSInvocation *)aSelector;
@end

Although of course no such protocol exists. Hehe.

Now, before the grand finale, the forwarding path in full, we need to look at one more crazy-message-receiving monster, Dr. NSZombie.

Zombies

Choo __unsafe_unretained *aChoo = nil;
@autoreleasepool {
  aChoo = [Choo new];
}

NSLog(@"%@", [aChoo blessYou]);

That's most certainly a dangling pointer (read the post on ARC if it isn't clear why). The object it has pointed to has died and the pointer is left roaming the world as an undead pointer, called a Zombie in Objective-C. The autoreleasepool is used to make sure that the cleanup of the object has occurred and that we are in possession of a real, bona fide zombie.

NSZombie

Running that code snippet will simply crash but if you enable NSZombies then it will give a nice error message before crashing.

*** -[aChoo blessYou]: message sent to deallocated instance 0xadd9e58

The idea is that objects are never actually deallocated when zombies are enabled. Their teardown still released all instance variables and any retained associated objects as well as calling the deconstructors on C++ instance variables. But when zombies are enabled, the final step, a free of the malloc'd memory inhabited by the instance, is skipped.

So then how are Zombies implemented?

The Implementation Requirements of NSZombie

To have the behavior of Zombies seen above there are three requirements.

The first is actually implemented the cleanup behavior described in the previous paragraph. This is implemented in the method _dealloc_zombie, which is a category on NSObject (defined in CF!) that is swizzled in when Zombies are enabled, by calling objc_destructInstance which is identical to object_dispose expect that it skips the free.

The second requirement is that the object have its class changed to NSZombie which is also done in _dealloc_zombie by calling object_setClass.

The final requirement is that the object log an error and then stop the app. The stopping part is simple. It can throw an exception, abort, exit, kill, etc. On x86 it executes the INT3 instruction directly to stop the app in the debugger (smart!).

Storage of the Old Class in NSZombie

There are actually two subtle issues that need to be addressed. First, once it changes the class of the object, it has no way to get it back when it logs the error. It can't actually store the old name directly in the instance because it is very possible that the instance had no instance variables and thus there is no room to do so!

One possible solution would be to use a global table of all zombies. This would quickly bloat to contain every object that has ever lived and died and is just not sustainable, even when debugging.

Instead, the implementation uses a public method in the Objective-C runtime that it advises no one ever actually call directly, lol, objc_duplicateClass. This is roughly equivalent to calling objc_allocateClassPair and then objc_registerClassPair right after it except that it makes tons of optimizations since it knows that you won't be adding method, ivars, properties, or protocols to the class.

This means that it creates a subclass at runtime for the class of every instance that becomes a zombie, of course with a giant cache of all the _NSZombie_ subclasses. And what does it use for the name of the class? A concatenation of the _NSZombie_ and the name of the class that the object was. It stores the old class name IN the new class name. 

If you dump all classes at runtime with objc_copyClassList in the example above, you'll definitely see _NSZombine_Foo. You can also see it by calling object_getClass on the ZombieThat's some nifty, clever stuff.

The Methods of NSZombie

The second subtlety comes when considering the methods that _NSZombie_ has. The first question has to be what the superclass is, since that will determine a set of the methods. It derives from neither NSObject nor NSProxy; if it did then it would have to implement all the methods from its superclass and in each log and halt. This is not ideal and will break with any additions of methods to the superclass (including categories!). Clearly then the only possible solution is that _NSZombie_ is a root class, meaning that it has no superclass.

Given the explanation above about the "secret" protocol, all it really needs to do is implement methodSignatureForSelector: and then log and throw. While this is arguably possible, it is semantically and pedantically wrong for a number of reasons, in decreasing order of danger:

  1. Is it neither correct nor safe to call any method on a Zombie ever. Imagine a future compiler change in ARC where self is retained across a method call. The program would die in objc_storeStrong.
  2. Such an implementation relies completely on the knowledge that methodSignatureForSelector: is all that is necessary for this to work. Using this detail is fragile and makes the pedant in me writhe.
  3. On failure the stack trace would reside arbitrarily inside of methodSignatureForSelector:. Leaking such an implementation detail would be gross, unnecessary, and easily confusing.

This leaves us with only one possible conclusion. Core Foundations forwarding path explicitly checks for the presence of a Zombie. It can't call isKindOfClass: because of problem number (1) above. It could call object_getClass and then call isSubclassOfClass: on that, but once it finds that it is a Zombie it will need to get the class name to extract out the old class name anyway so it might as well just get the name and check for the "_NSZombie_" prefix. Let's attempt to see if that is the case by fooling it.

Compiled with MRR (-fno-objc-arc)

NS_ROOT_CLASS
@interface _NSZombie_Apocalypse
@end

@implementation _NSZombie_Apocalypse
@end

int main(int argc, char *argv[])
{
  Class klass = object_getClass("_NSZombie_Apocalypse");
  _NSZombie_Apocalypse *zombieImpersonator = class_createInstance(klass, 0);
  NSLog(@"%@", zombieImpersonator);

  return 0;
}

So here a cute little program meant to fool the runtime. It creates a class whose name starts with "_NSZombie_". The class must be declared as a root class, otherwise the computer will wag its finger. Then we create an instance of the class; notice that we can't use newallocinit, or even class because we haven't written any of those methods. Hehe. We also have to compile it with MRR because class_createInstance is not available in ARC.

If we run this code with the class name as Not_NSZombie_Apocalypse then the output is

*** NSForwarding: warning: object 0xaddres58 of class 'Not_NSZombie_Apocalypse' does not implement methodSignatureForSelector: -- did you forget to declare the superclass of 'Not_NSZombie_Apocalypse '?
*** NSForwarding: warning: object 0xaddres58 of class 'Not_NSZombie_Apocalypse ' does not implement doesNotRecognizeSelector: -- abort

which is exactly what we would expect. But when the class is _NSZombie_Apocalypse then we get

*** -[Apocalypse  respondsToSelector:]: message sent to deallocated instance 0xaddres58

and we having correctly tricked the runtime into thinking that we have a Zombie!

Core Foundation's Forwarding Path in Full (Almost)

After everything we've seen we are finally ready to put together an almost-complete implementation of Core Foundation's forwarding path.

This takes what we had before and adds the preamble, the Zombie-check, if-guards that call class_respondsToSelector, and a number of error messages that the report when methods do not exist or are implemented as expected.

Perhaps the most fun check is that _objc_msgForwardStret was never called from objc_msgSend and likewise that _objc_msgForward was never called from objc_msgSendStret (this is the "structed-ness" check below).

There is also a guard to ensure that the invoked selector is already registered with the runtime. It simply registers the selector and then verifies that it got the same selector back. Its purpose is to protect some loon from passing a C-string in place of a SEL

objc_msgSend(anObject, (SEL)"doThings:", things);

This is not impossible, and the cast is valid, since under the hood a selector is really just a C-string. Though each selector has a single, unique, registered static address and using any lexically equivalent string will simply not work.

The @selector directive tells the compiler to place corresponding string in the data section of the binary and register it as a selector with the runtime. You can register your own strings using sel_registerName and sel_getUid, if you are nuts/adventurous and want to. The distinction between those two methods dies over the years and now their implementations are identical.

Aborting Warnings

The part of the forwarding path that tickles me the most is that the only call to CFLog that passes kCFLogLevelError is the zombie call. All of the rest of the logs statements are emitted at the warning level, even though they log that they intend to abort and then they absolutely do.

When I was a kid a warning was something just a bit softer.

Curtain Falls

That's all folks.

void __forwarding__(BOOL isStret, void *frameStackPointer, ...) {
  id receiver = *(id *)frameStackPointer;
  SEL sel = *(SEL *)(frameStackPointer + 4);

  Class receiverClass = object_getClass(receiver);

  if (class_respondsToSelector(receiverClass, @selector(forwardingTargetForSelector:))) {
    id forwardingTarget = [receiver forwardingTargetForSelector:sel];
    if (forwardingTarget) {
      return objc_msgSend(forwardingTarget, sel, ...);
    }
  }

  const char *className = class_getName(object_getClass(receiver));
  const char *zombiePrefix = "_NSZombie_";
  size_t prefixLen = strlen(zombiePrefix);
  if (strncmp(className, zombiePrefix, prefixLen) == 0) {
    CFLog(kCFLogLevelError,
          @"-[%s %s]: message sent to deallocated instance %p",
          className + prefixLen,
          sel_getName(sel),
          receiver);
    <breakpoint-interrupt>
  }

  if (class_respondsToSelector(receiverClass, @selector(methodSignatureForSelector:))) {
    NSMethodSignature *methodSignature = [receiver methodSignatureForSelector:sel];
    if (methodSignature) {
      BOOL signatureIsStret = [methodSignature _frameDescriptor]->returnArgInfo.flags.isStruct;
      if (signatureIsStret != isStret) {
        CFLog(kCFLogLevelWarning ,
              @"*** NSForwarding: warning: method signature and compiler disagree on struct-return-edness of '%s'.  Signature thinks it does%s return a struct, and compiler thinks it does%s.",
              sel_getName(sel),
              signatureIsStret ? "" : not,
              isStret ? "" : not);
      }
      if (class_respondsToSelector(receiverClass, @selector(forwardInvocation:))) {
        NSInvocation *invocation = [NSInvocation _invocationWithMethodSignature:methodSignature
                                                                          frame:frameStackPointer];
        [receiver forwardInvocation:invocation];

        void *returnValue = NULL;
        [invocation getReturnValue:&value];
        return returnValue;
      } else {
        CFLog(kCFLogLevelWarning ,
              @"*** NSForwarding: warning: object %p of class '%s' does not implement forwardInvocation: -- dropping message",
              receiver,
              className);
        return 0;
      }
    }
  }

  const char *selName = sel_getName(sel);
  SEL *registeredSel = sel_getUid(selName);

  if (sel != registeredSel) {
    CFLog(kCFLogLevelWarning ,
          @"*** NSForwarding: warning: selector (%p) for message '%s' does not match selector known to Objective C runtime (%p)-- abort",
          sel,
          selName,
          registeredSel);
  } else if (class_respondsToSelector(receiverClass, @selector(doesNotRecognizeSelector:))) {
    [receiver doesNotRecognizeSelector:sel];
  } else {
    CFLog(kCFLogLevelWarning ,
          @"*** NSForwarding: warning: object %p of class '%s' does not implement doesNotRecognizeSelector: -- abort",
          receiver,
          className);
  }

  // The point of no return.
  kill(getpid(), 9);
}

Postscript: The forwarding Path Isn't Open Source

It's a sad fact but it's true. It lives in the private part of Core Foundation. Sad panda!

A lot of the code in this post was put together with patience knee-deep in disassembly and poking around in Xcode + LLDB. Teasing out all the details was a great adventure for me and I hope it has been for you too.

Why objc_msgSend Must be Written in Assembly

Every message send in Objective-C is compiled into a call to objc_msgSend, a function that is called with the arguments as the message sense but with the receiver and the selector as the first two. So the line

[receiver message:foo beforeDate:bar];

will be compiled into to just call a C function:

objc_msgSend(receiver, @selector(message:beforeDate:), foo, bar);

There are many excellent write-ups on how the method is implemented or how it has evolved over the years, but I'd like to focus on one aspect that I haven't seen given too much attention:

It is not possible to implement objc_msgSend in C, Objective-C, or C++.

The Return Type

Consider the following two lines

NSUInteger n = [array count];
id obj = [array objectAtIndex:6];

which will be compiled as two C function calls.

NSUInteger n = objc_msgSend(array,  @selector(count));
id obj = objc_msgSend(array, @selector(objectAtIndex:), 6);

However there is no possible function that could actually satisfy both calls. Does it return an NSUInteger or an id?

The above two lines won't even compile. Whoops! Let's cast a slightly better lead.

NSUInteger n = (NSUInteger (*)(id, SEL))objc_msgSend(array,  @selector(count));
id obj = (id (*)(id, SEL, NSUInteger))objc_msgSend(array, @selector(objectAtIndex:), 6);

That's a little gross but at least it compiles. objc_msgSend is publicly available and declared in <objc/message.h>. If you do call it directly you will have to cast it in exactly this manner to appease the compiler,  but how on Earth is objc_msgSend implemented to support multiple return types?! We'll come back to it.

The IMP

The essence of objc_msgSend is quite simple. Given a receiver and a selector it does as follows:

  • Get the class of the receiver
  • Look for the selector in the method table
  • If found, return it
  • Else look at the superclass and repeat (until there is no superclass)

It's a pretty simply process that just walks up the inheritance hierarchy looking for the function pointer, the IMP, for the given selector. There's caches at each class level, but hey, that's just an implementation detail!

The Arg Types and Count

Once objc_msgSend finds the function pointer it just needs to call it with the given args. What remains is to find a way to call an arbitrary function pointer on some numbers of arguments any set of types. The number of arguments is easy to account for. We could put them into varargs and then call a function with them. But if we did that, every Objective-C method would have to pull its arguments out of varargs in a hidden prologue and that would just be terrible and unnecessary.

In C, calling a function is compiled into instructions for setting up the arguments (putting them in registers or on the stack) and then a jump/call to the address of the function. If we want to support any possible method signature we would have to write a switch statement that contained every possible combination so that we would have the code to properly sets up the arguments for any and every method signature. This simply does not scalable and is not possible.

Unwinding the Call

The solution that objc_msgSend uses comes from the fact that the arguments were setup correctly for the call into objc_msgSend. Said another way, objc_msgSend began with a stack frame and register combination exactly equal to the one that will be needed by the IMP that it finds.

Consider again the line

id obj = objc_msgSend(array, @selector(objectAtIndex:), 6);

which needs to setup 3 arguments: the receiver, the selector, and the index. By insisting that the IMP that we find have the same signature we know that just moments ago the world was as we needed! So, once it finds the IMP it puts everything back the way it was (something functions do before returning anyway, called the function epilogue) and then simply jump to the address of that function pointer that was found for the given selector. All the arguments will be setup correctly and the function can go on its merry way.

That IMP will end up correctly setting the return value (on x86 and arm it just gets stored in a specific register, eax/rax or r0, respectively) and we don't have to worry about the return value issue discussed above.

Wrap Up

Taking all of the rambling above and spinning it into a single statement would produce: calling a function in C requires the signature to be known for each call-site at compile-time; doing so at run-time is not possible and so one must drop down into assembly and party there instead.


Update:

It was pointed out that objc_msgSend could likely be implemented using the GCC extensions __builtin_apply_args, __builtin_apply, and __builtin_return. This is definitely true and points out the fact that such builtins were necessary to add since the language was not capable of the expressing the behavior on its own. The tricks needed to implement objc_msgSend would be the same tricks needed to implemented those builtins. The point of this writeup was not to get philosophical about what is or is not really C; the point was that objc_msgSend resides in a strange territory in the land of function calling and it felt fun to point out. :D

A Tiny Bit on Objective-C BOOLs

Note: This entire discussion applies only to the 32-bit run-time. In the 64-bit run-time BOOL is actually _Bool and is a real type. :D

It doesn't take very long with Objective-C to start using BOOLs. There are already many awesome discussions out there on their subtle, obnoxious behavior, with the following being two of the best:

There are specific issues that even appear within Apple's code that have not been widely discussed (as far as a quick web search is concerned) so here's a quick digest on two specific hazards dealing with bit fields.

Signed Char

For historical reasons BOOLs are typedef'd to signed chars, yes signed! This is super important because they are not native types; they are simply a typedef. That means the compiler can't really help ensure they behave anything differently than a signed char. Whoops!  That means you can put the value 7 in a BOOL. What does it mean? Well, read on!

1-Bit BOOLs Are Never YES

In C an n-bit signed integer will take on any value in the range [-2n-1, 2n-1-1].

An 8-bit signed integer then is anywhere in the range [-128, 127] and a 16-bit is in [-32768, 32767].

This is something most C programmers are more than familiar with. But what about a signed 1-bit integer? Given the formula above, it must be in the range

[-21-1, 21-1-1] = [-20, 20-1] = [-1, 0].

It can only be -1 or 0! It can not be the value 1 which means that it cannot be YES. This might not seem so bad until you look at a common pattern, bit fields.

struct {
  ...
  BOOL enabled:1;
} flags;

A BOOL semantic only needs one bit, since it only takes on values, so we often pack them into bit-field as shown. The only problem is that this flag can never be YES.

flags.enabled = YES;

if (flags.enabled == YES) {
  // Never going to get in here!
}

Total comedy, right? Of course there are two solutions. One would be to never compare to YES (something you should never never do anyway).

flags.enabled = YES;

if (flags.enabled) {
  // We'll make it here!
}

The above solution is absolutely correct and is exactly what all callers should be doing. But there is another solution that can be implemented at the same time and gives silly callers a little bit of leeway: don't make 1-bit fields signed.

struct {
  ...
  unsigned int enabled:1;
} flags;

You can use int or char or whatever integral type you want. It doesn't matter since you are only using 1-bit, but whatever you do, make sure it's unsigned! :D

You Need a Not-Not

So now that callers are protected it would seem as if the world has been made safe. Unfortunately the use of "bits" is still dangerous and feet will still be shot by the person they are attached to.

flags.enabled = value & 0x2;

if (flags.enabled) {
  // Did we make it here?
}

At first glance this should seem very natural. We want to know if one of the bits is set so we use a bit mask and store the result with an and. Sadly, that masking operation is going to return 0 or 2 both of which will be stored as 0 in the enabled field. Yay for integer truncation!

Worse yet, that means that storing any even integer into enabled will be NO and any odd integer will be YES. That's an API to tell your grandchildren about!

UIScrollView *scrollView = [[UIScrollView alloc] init];
int n = ...;
[scrollView setPagingEnabled:n];

if (scrollView.pagingEnabled) {
  // Did we make it here?
}

This is a real problem. The if-statement above will evaluate to true only if n was odd. So we need a healthy way to convert integers into BOOLs. We can't use a cast

UIScrollView *scrollView = [[UIScrollView alloc] init];
int n = ...;
[scrollView setPagingEnabled:(BOOL)n];

if (scrollView.pagingEnabled) {
  // Did we make it here?
}

because it is still literally, and now explicitly, a truncation of the bits in n. Time for a not-not!

UIScrollView *scrollView = [[UIScrollView alloc] init];
int n = ...;
[scrollView setPagingEnabled:!!n];

if (scrollView.pagingEnabled) {
  // We're in here as long as n != NO.
}

We could have also used an expression like (n > 0) which is just as valid. The real troublesome bit is that we actually have to do this. Why doesn't the setPagingEnabled: method do this for us?! Well, imagine that every time you wrote a method that takes a BOOL that you had to not-not it. Oy! It'd be time to switch languages at that point.

So, BOOLs have a secret, implicit contract that anyone using them enforce that they contain no value other than 0 or 1. Yes, that is on you the developer. Neither the frameworks nor the compiler will help you. Some times to use Objective-C safely you really have to know too much a lot.

The Amazing Adventures of NSArray

Let's start with something absurd.

[[NSArray alloc] isKindOfClass:[NSMutableArray class]];
[[NSMutableArray alloc] isKindOfClass:[NSArray class]];

It turns out that both of these lines are true. Feel free to try it out but have a bucket ready nearby in case your brain starts leaking; it's more than kindOfCrazy.

Peeking into Foundation

Compared to many other languages, Objective-C is just plain funky. The syntax is actually quite small and leads to a lot of patterns being implemented via trickery (reread those two lines above). But by reading, poking, prodding, probing, and exploration the classes the Apple has written it is easy to get insight into some of the more common patterns as well as some of the tricks that at first seem quite bizarre.

Looking at just NSArray, NSNumber, NSString, NSDictionary, and NSObject (or Foundation in general) will reveal tons of tricks and patterns that are both intriguing, educational, and a healthy dose of fun. For this post we'll focus on the insanity that lies within NSArray. Here's some of what will be explored:

  • Literal Syntax
  • Subscripting
  • Class Clusters
  • Toll-free Bridging
  • Indexed Ivars

Literals

Literals are the easiest "magic" to digest that surrounds NSArray. They're relatively new to the language, added in Clang 3.5. The syntax is quite simple:

NSArray *a = @[ foo, bar, baz ];

and is just a literal translation (pun intended) to the following array construction.

id objects[] = { foo, bar, baz };
NSArray *a = [[NSArray alloc] initWithObjects:objects count:3];

Unfortunately there are no hooks to tap into such syntax. It's only available for NSArray and NSDictionary and so there isn't much more to do with it.

Subscripting

Clang 3.5 also added support for using square brackets for subscripting.

IndexedContainer *ic = ...;
ic[3] = @"foo";
id obj0 = ic[5];

KeyedContainer *kc = ...;
kc[@"qux"] = @"bar";
id obj1 = kc[@"bazzle"];

It's super simple and just results in a simple translation that depends on the subscript being an integral type (indexed) or an object (keyed).

IndexedContainer *ic = ...;
[ic setObject:@"foo" atIndexedSubscript:3];
id obj0 = [ic objectAtIndexedSubscript:5];

KeyedContainer *kc = ...;
[kc setObject:@"bar" forKeyedSubscript:@"qux"];
id obj1 = [kc objectForKeyedSubscript:5];

This code is identical to the previous block but its easier to read. Thankfully NSArray and NSDictionary implement these methods as we'd expect and suddenly things feel just a little nicer.

Inspecting the Memory of a Constant Array

Let's construct a simple, constant array. (Note that everything that follows is being compiled and run on a 64-bit architecture - it doesn't matter if it's iOS or OS X).

NSArray *array = @[ @"one", @"two", @"three" ];

The object that we get it really just a pointer to a region of memory (note the asterisk). Typically we acknowledge the pointer-ness of Objective-C objects as nothing more than an implementation detail, but it is fun to wonder what the memory region that it points to looks like. Let's start by finding out how large the memory region that we are looking at is.

#import <objc/runtime.h>

NSLog(@"%lu", class_getInstanceSize([array class]);

> 16

Alright, so there's 16 bytes in there. The first 8 are the isa pointer, as is for every object, so that leaves only 8 more bytes to actually look at. Within those 8 bytes we hope to find some semblance of the structure of an array (such as a length and an actual id*, or something similar).

Let's look at the 8 bytes following the isa pointer and see if those look like a pointer, perhaps to some internal data structure just a simple buffer that holds the contents. (If you aren't sure why the bridge-cast was needed it might be worth reading my writeup on Objective-C ARC.)

char *bytes = (char *)(__bridge void *)array;
    
NSLog(@"%x", *(uint64_t *)(bytes + 8));

> 3

That looks promising. The length of the array we used was 3, but this might just be a coincidence. Let's try a few more lengths.

char *bytesArrayLen4 = (char *)(__bridge void *)@[ @1, @2, @3, @4 ];
NSLog(@"%x", *(uint64_t *)(bytesArrayLen4 + 8));

char *bytesArrayLen7 = (char *)(__bridge void *)@[ @1, @2, @3, @4, @5, @6, @7 ];
NSLog(@"%x", *(uint64_t *)(bytesArrayLen7 + 8));

> 4
> 7

Sweet, we found the length! But it's possible that the length is not actually stored in all 8 bytes and is really only in the first 4. So let's see what happens if we look at bytes 12-15 as an 4-byte integer.

NSLog(@"%x", *(uint32_t *)(bytes + 12));

> 0

Well darn. Either those bytes are not necessarily in use, represent an all-zero set of flags, or the length really is stored in a 64-bit quantity.

Hunting for the Rest of the Object

Regardless of what's going on, we have found a serious problem. The 16 bytes available contain the isa, the length, and not much more. Where on Earth are the actual elements?!

Perhaps there is a global map somewhere that maps array addresses to array contents. However if that is the case then I am just going to retire and give up on this insanity. Luckily that isn't the case. If you recall, we used class_getInstanceSize to find the size of the instance, but what if somehow the chunk of memory that we are looking at is actually bigger? Let's look at how big it is instead of how big we expect it to be.

#import <malloc/malloc.h>

NSLog(@"%lu", malloc_size(bytes));

> 48

Ummm what? Instances of this class are only supposed to be 16 bytes. Where did the the other 32 come from? Let's skip that question for now and look inside the next 32 bytes that we apparently have.

NSLog(@"%@", *(uint32_t *)(bytes + 16));
NSLog(@"%@", *(uint32_t *)(bytes + 24));
NSLog(@"%@", *(uint32_t *)(bytes + 32));
NSLog(@"%@", *(uint32_t *)(bytes + 40));

> one
> two
> three
> (null)

We found the contents. How fascinating, they are actually stored directly inline within the memory region that the array variable is pointing to. It's super easy to check that making an array of length 4 occupies that last slot. An array of length 5 or 6 will have a region of memory that is 64 bytes long, 7 and 8 is 80 bytes, and so on. The malloc-size is the smallest multiple of 16 that is large enough to hold the 8-byte isa, the 8-byte length, and then a pointer to each object in the array.

Here is a struct that has equivalent layout to a constant NSArray.

struct MyArray {
  Class isa;
  uint64_t length;
  id object0;
  id object1;
  id object2;
  ...
};

 

Allocating the Memory for an Instance

Now that we understand the layout we need to figure out how the memory became that large in the first place. Whoever allocated the memory clearly didn't just use class_getInstanceSize. There was a chunk of bytes added on at the end. Time to go crawl through <objc/runtime.h>, my favorite header. 

There appears to only be one method for creating an instance of a class.

id class_createInstance(Class cls, size_t extraBytes)

And it allows you to specify a number of bytes to throw onto the end. Setting a symbolic breakpoint on this function in LLDB shows that the extraBytes parameter is always n*sizeof(id) and the mystery is solved. There is also a function for getting the address of the chunk of extra bytes which we can use to see exactly what we'd expect at this point.

Compiled with MRR (-fno-objc-arc)

// object_getIndexedIvars is not available in ARC.

NSArray *array = @[ @"one", @"two", @"three" ];

void *indexedIvars = object_getIndexedIvars(array);

NSLog(@"%@", *(id *)(indexedIvars + 0));
NSLog(@"%@", *(id *)(indexedIvars + 8));
NSLog(@"%@", *(id *)(indexedIvars + 16));

> one
> two
> three

Suddenly the world is starting to make sense and we have unraveled that memory layout of a constant NSArray. It might seem like there are no surprises left but think carefully about when class_getInstanceSize could be called.

Let's use alloc-int directly instead of the container literal syntax so that we can get a grasp of what is happening.

id objects[] = { @"one", @"two", @"three" };
NSArray *a = [[NSArray alloc] initWithObjects:objects count:3];

The allocation, a call to calloc using the sized returned from class_getInstanceSize would be expected to occur in the call to alloc in the above snippet. But how does it possibly know what size to allocate? The information related to how big the array is doesn't appear until the init instance method is called on the already allocated region.

It is indeed possible that the init method releases the memory and allocates the correct size (see the discussion on init consuming self to understand why this is semantically acceptable) except that doing so would be incredibly wasteful.

To start with, let's inspect the object returned from the call to alloc. We have to return to MRR again because ARC will vomit if you call alloc but not init.

Compiled with MRR (-fno-objc-arc)

NSArray *array = [NSArray alloc];
NSLog(@"%lu", malloc_size(array));

id objects[] = { @"one", @"two", @"three" };
array = [array initWithObjects:objects count:3];

NSLog(@"%lu", malloc_size(array));

> 16
> 48

There's no arguing that. Clearly a new piece of memory is being returned from the init method. How wasteful... :'( Although perhaps we could return something intelligent from alloc so that we don't have to waste it.

Class Clusters and Returning a Factory from Alloc

A sneaky thing to do would be to implement the alloc method to return a factory (which could easily be a global singleton if we wanted it to). Then implement the init methods on that factory to return new objects, allocated exactly as you need. This is exactly what NSArray does. Every time you call alloc on the NSArray class it returns a global instance of NSPlaceholderArray, the magical array factory.

This trick of returning a factory from alloc is actually quite common. It allows you to defer any allocation until the init method when you have all the information to construct exactly what you need. This allows such tricks as appending extra bytes to the instance or choosing a specific subclass to allocate.

The pattern of using a factory to instantiate a specific subclass is called a class cluster. The interface of an abstract class is used but in such a way that you could be dealing with any specific subclass without having to worry about it.

  • NSString is a cluster that creates instances best suited for the underlying characters (such as ASCII or UTF8).
  • NSNumber is a cluster that returns global singletons (such as for @YES and @NO), tagged pointers, or CFNumbers (good ol' toll-free bridging).
  • NSDictionary and the other collection classes also serve as clusters.

One of the primary concepts of a cluster is that you never actually have an instance of the abstract base class, but instead of some private subclass. In the case of the example that has been used to far, it is __NSArrayI, the "in-place" NSArray subclass.

NSLog(@"%@", [@[ @"one", @"two", @"three" ] class]);

> __NSArrayI

There's actually more than 20 subclasses of NSArray in Foundation alone. That's an impressive cluster. :D

NSPlaceholderArray

Now that we know that NSArray's alloc method returns a factory, it's worthwhile to examine the object in a little more detail. The object clearly has all of the init methods (since it uses them to create instances) but what exactly is it?

Well, it definitely should be an NSArray. Returning something from alloc that wasn't one sounds completely nonsensical although only in the most pedantic of reasoning. Thus it's fair to assume that NSPlaceholderArray is a subclass of NSArray, but this causes some subtle trickery.

It turns out that for all the same reasons explained so far the alloc method on NSMutableArray also returns an NSPlaceholderArray singleton (not the same one though). This means that NSPlaceholderArray must also be a subclass of NSMutableArray, and it is. The inheritance hierarchy is thus:

NSArray ← NSMutableArray ← NSPlaceholderArray

Which leads to the silliness of both these two lines being true:

[[NSArray alloc] isKindOfClass:[NSMutableArray class]];
[[NSMutableArray alloc] isKindOfClass:[NSArray class]];

And so are both of these lines:

[[NSNumber alloc] isKindOfClass:[NSValue class]];
[[NSValue alloc] isKindOfClass:[NSNumber class]];

Since NSNumber and NSValue are both class clusters that return a factory from alloc and have the inheritance hierarchy:

NSValue ← NSNumber ← NSPlaceholderValue ← NSPlaceholderNumber

If you think carefully about this you'll see that means that the object returned from NSValue's alloc method is a subclass of NSNumber. So, can we NSPlaceholderValue to vend an NSNumber for us?

NSLog(@"%@", [(id)[NSValue alloc] initWithInt:8]);

> *** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** initialization method -initWithInt: cannot be sent to an abstract
object of class NSPlaceholderValue: Create a concrete instance!'

Darn it's too smart for us.

The Adventure Ends

Hopefully you enjoyed this somewhat unusual look into the internals of an Objective-C class. Looking into Apple's classes reveals a plethora of common and uncommon tricks. Learning about them is not only fun but helps understand how impressive and expressive the language actually is. If any of this actually changes any of the code that you are writing then I would love to know what on Earth you are doing. But at least now you know.

The Syntax of Objective-C Blocks

Even after writing Objective-C for years it can be tricky to remember the exact details regarding the syntax for blocks. There's a couple parenthesis and a caret. The exact ordering though is easily forgotten and worse yet there appears to be six unique incantations.

Luckily there are actually only two and remember why they are they way they are should help to remember the syntax that next time that you go to use blocks.

Pointers in C

Objective-C is nearly a strict superset of C. Only a few rules have been altered and really to relax a few constraints (such as not enforcing functions to be declared before use if used within an @implementation). What matters most here is that Objective-C uses the exact same syntax for pointers as C does without any exception. Here's a quick refresher of a few example type declarations and an equivalent declaration for a pointer of the same type.

TypePointer to Type
int i;
int *i;
float f[];
float *f[];
char c[][];
char *c[][];
uint8_t *u[];
uint8_t **u[];
struct Foo f;
struct Foo *f;

The pattern is easily recognizable - the language was designed that way - you simply put an asterisk immediately to the name and it becomes a pointer to the type that it was.

Let's try to apply the same logic to the declaration of a function.

float someFunction(int);

If we mimic the pattern we would precede the function name with an asterisk.

float *someFunction(int);

Unfortunately the parse-rules of C are not on our side now. The asterisk is treated as bound to the return type and now we have a function that returns a pointer to a float. It is still a function, that now returns a pointer, instead of it being a pointer to a function itself.

We need a way to tell the compiler that the its rules of precedence do not apply correctly in this instance. How do we tell the compiler to group items differently than is standard? Parenthesis!

float (*someFunction)(int);

Success! We have simply told the compiler exactly how the asterisk should be bound in the expression.

This leads to a simple trick for remembering how to write a function pointer:

Write the function declaration for the type of function that you want to point to and precede the name with an asterisk. Don't forget to add parenthesis to force the compiler to bind the entire type as the pointer instead of the return value.

Following that logic we can easily produce the syntax for the declaration of the type alone, without needing to specify a particular name.

float (*)(int);

This is the declaration of a particular type of function pointer (one that takes an int and produces a float).

Reading a Function Pointer

Remembering a function pointer as a function, plus an asterisk, plus a set of parenthesis should enable you to remember it after applying it a few times (instead of just looking it up, in which case you'll never actually learn it). But there is another way to look at function pointers, which easily applies to all types in general, where you build the type from inside-out.

Here is a type
someFunction
that is a pointer
*someFunction
to a function
(*someFunction)()
that takes an int
(*someFunction)(int)
and returns a float.
float (*someFunction)(int);

This can be helpful for constructing more complex expressions, but requires more subtlety than the previous suggestion for remembering the syntax.

Functional Function Syntax

When a function is treated as a type it can be the value stored in a variable via which it can be passed around like any other value. Thus just like any other type there are 5 situations in which it can appear:

1. Declaration
float (*someFunction)(int);
2. Typedef
typedef float (*my_int_to_float_t)(int);
3. Class Property
@property (assign) float (*function)(int);
4. Function Argument
float applicator(int i, float (*func)(int));
5. Selector Argument
- (float)applyFunction:(float (*)(int))func toInt:(int)i;

It should be apparent that 1, 2, 3, and 4 are all exactly the same. They are all the syntax for the declaration of a function pointer used in 4 different context. The 5th item is actually the exact same syntax as well but with one slight difference.

Each argument in a selector is written with the type in parenthesis followed by the name of the variable. Thus the 5th item is the exact same as the previous 4 except that declares the type without a name, wraps it in parenthesis, and then puts a name after it.

The most important takeaway from all of this is that there is only ONE syntax relating to function pointers. The 4th item could also be written to omit variable names (since they are not required in function declarations).

float applicator(int i, float (*func)(int));
float applicator(int, float (*)(int));

Both of those are equivalent and we see one last time that there is only one syntax at play.

Blocks

Clang 3.5 added support for blocks also known as anonymous functions, closures, or lambdas. The specification focuses on two critical pieces of syntax, the declaration and the definition of blocks.

declaration is an expression that tells the compiler about a type. It tells it in which expressions it can appear and what the semantics of its use are.

definition provides the actual information/implementation of a given symbol.

In the expression int i = 4; the int i part is the declaration and the i = 4 is the definition. A function prototype or an externed constant are both examples of declarations. The actual implementation of a function or the contents of an externed constant are the definitions.

Declaring Blocks

So far we have looked closely at the declaration of function pointers. Let's look at the same 5 uses of blocks as we did function pointers above.

1. Declaration
float (^someBlock)(int);
2. Typedef
typedef float (^my_int_to_float_t)(int);
3. Class Property
@property (assign) float (^block)(int);
4. Function Argument
float applicator(int i, float (^block)(int));
5. Selector Argument
- (float)applyFunction:(float (^)(int))func toInt:(int)i;

The syntax is exactly the same as for function pointers except that the asterisk became a caret. Literally there is no difference. Every expression involving the declaration of a block is identical to an expression with a function pointer of the same signature except with the change that the asterisk becomes a caret!

Thus the actual type of all of the blocks above is

float (^)(int);

and so that is what you end up seeing as the type in parenthesis for the 5th item, the use as an argument-type in a selector.

Likewise, the 4th statement could again be used without variable names in the function and you you two equivalent statements.

float applicator(int i, float (^block)(int));
float applicator(int, float (^)(int));

Defining Blocks

There are only two pieces of block syntax remaining. One of the two is __block which I am not going to discuss here. That leaves only one final piece of syntax, the actual definition of a block. Luckily, this one is the easiest piece of syntax. Consider the caret to be a unary operator that takes a function with no name and produces a block object. It's that simple.

^float(int i) {
 return i * 2.0;
};

Compare it to the equivalent C function.

float aFunction(int i) {
 return i * 2.0;
}

To make it into a block all you do is omit the name, turning it into an anonymous function and pass it to the unary caret operator. Since this produce an object you have to end in a semicolon.

Putting it all Together

That's all there is to it. That is the syntax of blocks and there is nothing more.

Let's look at an example in full to ensure that the syntax sticks.

float (^aBlock)(int) = ^float(int i) {
 return i * 2.0;
};

The left side of the equals, the declaration, is just like a function pointer in C except that the asterisk became a caret. And remember that the syntax of a function pointer is just that of the function with an asterisk and a set of parenthesis to enforce the binding of the pointer to the type.

The right side of the equals, the definition, is the unary caret operator applied to an anonymous C function.

So, here's all the block syntax there is.

1. Declaration
float (^someBlock)(int);
2. Typedef
typedef float (^my_int_to_float_t)(int);
3. Class Property
@property (assign) float (^block)(int);
4. Function Argument
float applicator(int i, float (^block)(int));
5. Selector Argument
- (float)applyFunction:(float (^)(int))func toInt:(int)i;
6. Definition
^float(int i){ ... };

There appears to be six unique variants to remember but there aren't, there are two, each of which is easily deducible if you remember where the syntax comes from.

Coping with and Learning Block Syntax

If you go and look up block syntax every time that you need to use it, then you'll never remember it. Instead try to work through it and remember the reasoning behind it. If you do need to reference the syntax then come do it here since it will be a reminder of how you yourself can recall it in the future.

As you begin to try to digest this syntax, allow me to leave you with something absurd. What would it look like to have a block that returns a block?

int(^(^scalingFactory)(float))(double) = ^int(^(float a))(double) {
  return ^int(double b) {
    return a * b;
  };
};

Good luck trying to apply the syntax rationale discussed here to this particular situation. Sometimes the embedding of types becomes so unruly that you should just use a typedef and call it a day.

typedef int (^my_double_to_int_t)(double);

my_double_to_int_t (^scalingFactory)(float) = ^my_double_to_int_t(float a) {
  return ^int(double b) {
    return a * b;
  };
};

Don't let the syntax block you. Learn it. Apply it. Party.

An Aside on Init's Consumption of Self

Alloc's Retain Semantics

Let's play!

 [SomeClass alloc];

You've probably not seen that line of code before. At least not alone.

The returned memory is uninitialized since it has not yet had an -init* method called. It has the minimum it needs to make it to the init method. This is nearly always a calloc'd region of memory large enough to hold an instance of the class with the isa field set (which class it is).

What is its retain count? Is it zero? Wouldn't that mean that it's deallocated? It can't be a zombie...

But can you release it? Let's take a look:

 NSLog(@"%lu", [[SomeClass alloc] retainCount]);

> 1

In retrospect, of course it is one. It *must* be one; no other number makes sense.

 [[SomeClass alloc] init];


What is its retain count?

If init retains self then the retain count would be 2. If init doesn't retain self then we have a very subtle and interesting potential leak.

Alloc and Init Can't *Both* Retain

Compiled with MRR (-fno-objc-arc)

 1 id temp = [SomeClass alloc];
 2 id obj = [temp init];
 3 ...
 4 [obj releasse];

Let us assume that init does NOT retain the object. Then in the case where temp != obj, who deallocated temp? If temp's init method returns a different object than temp then it is leaked!

Here's a case where the init method might return a different object.

Compiled with MRR (-fno-objc-arc)

 1 - (instancetype)init
 2 {
 3   [self release];
 4   self = [[SomeOtherClass alloc] init];
 5   return self;
 6 }

This method clearly releases the initial memory and so the leak is avoided. But we haven't actually yet been able to determine whether a retain would come from SomeOtherClass's init method. Even if it doesn't retain the object we still have [SomeOtherClass alloc] as a +1 and this method returns a +1 object. That's already a problem. We now appear to have both the alloc and the init method returning +1. Unfortunately even though we released the old value of self and prevented a leak and everything appears balanced. It is no longer possible to describe the behavior of the init method... =\

Remember that every Objective-C method has two hidden arguments, the receiver and the selector.

 - (instancetype)initWithObject:(Object *)o;

becomes equivalent to C function with the prototype

 id _initWithObject(id self, SEL _cmd, Object *o);

We can document this method for both cases of returning the first argument or a new one.

This method has two possibilities:

  • it returns self

  • it released self and return another object

Luckily the use of retain/release are equivalent and the program does not leak. :D

Ugh yuck! How would you explain that to a compiler?! Oof! Let's look at those two statements again.

  • it returns self

  • it releases self and returns a new object

And emphasize the retain count of the object returned.

  • it returns self

  • it releases self and returns an object that is owned/retained (you must release it!)

It's the same statement but with a reminder. Let's change the first to do a retain and then a release. It's completely silly and wasteful, but run with it for a moment.

  • it returns [[self retain] release];
  • it releases self and returns an object that is owned/retained (you must release it!)

That's silly but it works. But if you look carefully at those two lines they are equivalent. They both release the input argument and returns a retained object that you must later release.

So if this method were just documented semantically it could say the one line:

  • it consumes self and returns a retained object

The word releases was also changed to consume because that is the vocabulary for a function that releases one of its arguments.

Consumption

The init method releases the first argument and returns a retained object. It may be able to optimize away any superfluous retains and releases (by returning self with retaining or releasing it) but that is an implementation detail. ;)

Thus the init method is equivalent to the source line

- (instancetype)initWithObject:(Object *)o
    __attribute__((ns_consumes_self))
    __attribute__((ns_returns_retained));

but the method is known to have those two attributes since it is in the init method family and they're redundant. Those two attributes could also be replaced with the macro NS_REPLACES_RECEIVER.

A semantically equivalent C function would look something like this:

 id _initWithObject(id __attribute__((ns_consumed)) self, SEL _cmd, Object *o)
    __attribute__((ns_returns_retained));

So in summary, alloc returns a retained argument, init returns a retained argument, but init releases the argument too.

So in [[SomeClass alloc] init] you have:

Compiled with MRR (-fno-objc-arc)

 1 id temp = [SomeClass alloc];
 2 id obj = [temp init]; // This releases temp!
 3 ...
 4 [obj release];

And there are no leaks. Voilà!

So, the next time someone says to you "which method sets the retain count, alloc or init?" You can respond with "both do!" and then blow a raspberry. :)

Excessive Footnote:

P.S. In reality it is likely that neither retained it. When you retain an object for the first time it is added to a global table. Absence in the table means "retain count 1" and thus *nothing* actually needs to be done to setup up the retain count on creation. The best part of all is that the global table increments and decrements by two, keeping the value always even, so that it can use the the least significant bit of the count as the "is deallocating" flag.

Bridging the Gap on Objective-C ARC

Some Starting Words

 Objective-C has three memory management schemes:

  • manual retain release (MRR)
  • automatic reference counting (ARC) 
  • garbage collection (GC) 

Luckily, GC is dead and so there is no use to discuss it. However, it still is incredibly easy to stumble across both ARC and MRR wherever you go. Understanding ARC is critical to being an iOS or Mac developer these days and as it turns out its a little more involved than this graphic Apple made. The image's overall sentiment is correct and does give a basis for the difference in code: you no longer have to write retain and release explicitly. Yay! Now, we're done, right? 

Reference Counting

If you already know what reference counting is then feel free to skip this section.  I am going to keep it brief anyway, so if you have never heard of this concept, then you might want to read up elsewhere first.

Every object in Objective-C has a piece of state called its reference count. It is an unsigned integer that is used to keep track of the number of referents to the object and keep it alive until there are none. One could interpret this as to say that if an object has a reference count of 3 then there are 3 semantic scopes in which the object must be kept alive.

The rules of reference counting in Objective-C are as follows:

  • A created object has a retain count of +1 (usually from an -init method).
  • When the count is 1 and the object is released, it is deallocated. 
  • The -retain method increases the count by one. 
  • The -release method decreased the count by one. 

This arrives at some pretty standard patterns which can be summed up as "if you want to start using the object you must ensure that it is retained through your use." This manifests itself primarily in two ways:

  1. When you start using an object -retain it and when you finish, -release it.
  2. Never use an object without retaining it UNLESS you have retained another object that has retained it. In reality this is just repeating point #1 but with the transitive property.

Retained References

Then, with this is mind, we arrive at the standard retain-setter: 

Compiled with MRR (-fno-objc-arc)

 1  // A retain-setter (acquiring a "strong" reference)
 2  - (void)setFoo:(Foo *)aFoo {
 3    [aFoo retain];
 4    [_foo release];
 5    _foo = foo;
 6  }

The pattern is easily learned. We must release the old value (we are done with it), retain the new value (we want to start using it), and actually assign the pointer. This is the semantic handoff for replacing ownership (and we would release _foo in the -dealloc method to seal the deal).

The only point worth making is that the method must be implemented in the order shown. If aFoo happens to be the same pointer as _foo then we wouldn't want to release it and potentially have it be deallocated if the intent was to immediately retain it afterward (sorry, it's gone!). 

Unretained References

It's just as easy to make an assign-setter where we don't actually bump the reference count. That means that keeping this object alive is someone else's job. It could be deallocated and we'd end up with _foo being a dangling pointer. Un-retained objects must be handled with care.

Compiled with MRR (-fno-objc-arc)

 1  // An assign-setter (acquiring a "weak" reference)
 2  - (void)setFoo:(Foo *)aFoo {
 3    _foo = foo;
 4  }

Scope-Retained References

The only piece of MRR that remains is the method -autorelease. Often you want to create an object to return from a function (reminder: its retain count would be +1). Imagine this semi-contrived function:

Compiled with MRR (-fno-objc-arc)

 1  NSArray *ensureArray(NSArray *)object {
 2    if ([object isKindOfClass::[NSArray class]]) {
 3      return object;
 4    }
 5    return [[NSArray alloc] initWithObject:object];
 6  }

It is the responsibility of the caller to release the return value? In one branch a new object is created and in the other an existing object is returned. If the first branch executes and the caller releases the value at some point then the number of retains and releases will be unbalanced and the program will suffer an overrelease. If the second branch executes and the caller doesn't release it then the object will never be released and it will leak.

The problem is that the first branch return an unowned object  whereas the second returns an owned  object. There is no correct behavior for the caller. One possible solution would be to make all branches return an owned object.

Compiled with MRR (-fno-objc-arc)

 1  NSArray *ensureArray(NSArray *)object {
 2    if ([object isKindOfClass::[NSArray class]]) {
 3      [object retain];
 4      return object;
 5    }
 6    return [[NSArray alloc] initWithObject:object];
 7  }

While this works, it is unfortunate. This means that every branch of every method must return an owned reference and every caller of every function must release the return value. Ugh! Can you imagine all the bugs and chaos that would ensue?! 

Instead we want a way to return an unowned object. Sadly if we release the value in the second branch we'd end up deallocating the object before the method even returns. We need a way to say "release this in the future" such that there is sufficient time for the caller to retain it if desired or allow it deallocate and be forever forgotten.  

We arrive at autorelease. An autorelease-pool is a set that when "drained" send a -release message to all objects in it. Thus all we need to do is put our object into an autorelease pool that will drain at some point in the future. Luckily we don't have to worry about where the autorelease-pool is or when it drains (there's one created for each processed event in the event loop and you can create your own). We simply need to just call the -autorelease method and everything will work out in the end.

Compiled with MRR (-fno-objc-arc)

 1  NSArray *ensureArray(NSArray *)object {
 2    if ([object isKindOfClass::[NSArray class]]) {
 3      return object;
 4    }
 5    return [[[NSArray alloc] initWithObject:object] autorelease];
 7  }

Core Foundation

There is one more thing to go over before I go into ARC, since it causes the pain points and complexity of ARC: void pointers. 

All Objective-C objects are on the heap (yes, there are a few exceptions). That means that we refer to them via pointers and whenever you have pointers you are in The Wild West.  You can shove stuff into them, dereference them, add 4 and see what's next, and do any other crazy thing you want. When the compiler tries to figure out how to manage your memory for you it needs to make sure you don't go do any crazy pointer magic behind its back. But sadly you will because of a cute little animal called Core Foundation.

In reality it's just a bunch of C objects (meaning structs, pointers, malloced memory, and glue to hold it all together) with a bunch of C functions to operate on them. Many of the APIs are more feature-filled than objects in Foundation; so, they tend to pop up quite often. One example is CFMutableDictionaryRef:

Compiled with MRR (-fno-objc-arc)

 1  CFMutableDictionaryRef dRef = CFMutableDictionaryCreate(...);
 2  CFDictionarySetValue(dRef, aKey, aValue);
 3
 4    ...
 5
 6  CFRelease(dRef);

It behaves just like NSMutableDictionary except that it has a few extra bells and whistles. It even follows the same patterns of MRR. You can see that the "create" method returns a +1 object and that if must be CFReleased at the end (lest it leak).

Toll-Free Bridging

CFMutableDictionaryRef and NSMutableDictionary are more than just similar; they are essentially the same object. Under the hood they have the exact same data layout and are completely interchangeable. You are free to take either of the two, cast it to the other and use method from either on it. It's cool and it's crazy and when you add ARC to the mix, it's tricky.

Automatic Reference Counting (ARC)

A few years ago Apple introduced a new feature called ARC to the Objective-C language (here's the spec). The idea was that you would no longer need to call retain, release, or autorelease because the patterns had become so well established that the compiler could figure it out for you. For a lot of high-level application code (read: code nowhere near Core Foundation) this was basically true and the graphic shown at the top of this post (from Apple's transition guide) was basically true.

ARC added the ability to explicitly specify retained and unretained references directly and the compiler would handle the rest. Now you could write '__strong id Foo' and have a reference then when assigned to, would: release the old value, retain the new, and assign use primitive assignment for the actual value. Thankfully, all variables (including instance variables in classes) are strong by default; feel free to omit the qualifier.

Along with __strong they added __weak, for unretained pointers. And because "who doesn't love a magic show?" they made is so that __weak references were self-zeroing. That means that when the object gets deallocated all __weak references to it self-zero and become nil (it's actually just a memory barrier and a little bit of bookkeeping, but meh, call it magic).

So now the compiler figures out what to retain, what to release, what to autorelease (with some crazy runtime optimizations to avoid it), and then at compile time can optimize the numbers of calls to the minimum set needed for a given block of code. It's pretty cool, and well, I love my job. 

Hmmm... it's just got dark out. Oh! CF is here. 

Cast All The Things

Now that we're all ARC experts, let's look at some code! :D
Here's an example where a CFDictionaryRef and NSDictionary are used with Toll-Free Bridging.

 

Compiled with MRR (-fno-objc-arc)

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSDictionary *d = (id)dRef;
 4
 5    ...
 6
 7    [d release];
 8  }

Notice that the code is MRR and it works. dRef is created with a retain count of +1. Then after line 3 both d and dRef point to the same object which still has retain count +1. Finally at line 7 d is release, the retain count goes to 0, and the object is deallocated (remember, in reality there was only ever one object).

Let's use our awesome new knowledge and convert this to ARC.

Attempt at an ARC solution

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSDictionary *d = (id)dRef;
 4
 5    ...
 6  }

We just remove the -release call and we're done, right? Well, if we were dealing completely with NSDictionary and there was never any CF in sight, then that would be 100% correct, life would be too easy, and the header of that code snippet would not be yellow nor contain the word "attempt." 

So, what went wrong? Well, the problem is with the interaction of the calls that the compiler inserts and the Toll-Free Bridging.

There are a number of methods that are inserted during ARC compilation.  The most obvious three are objc_retain(id value)objc_release(id value), and objc_autorelease(id value). But there are some crazy cool ones like 

objc_retainAutoreleasedReturnValue(id value) and

objc_initWeak(id *object, id value), but we don't really care about those for this post.

The one that we are going to focus on quite a bit is 

objc_storeStrong(id *object, id value). It is semantically the equals operator when used with a __strong variable. It's behavior is equivalent to the following MRR:

Compiled with MRR (-fno-objc-arc)

 1  id objc_storeStrong(id *object, id value) {
 2    [value retain];
 3    id oldValue = *object;
 4    *object = value;
 5    [oldValue release];
 6    return value;
 7  }

I am not saying it is actually implemented that way, but oh well, close enough! Also notice that same pattern or releasing the old value, retaining the new value, and doing a primitive assignment. 

So, let's get back to that example. I'd like to remark that it won't even compile, but for now let's ignore that fact and I'll tell you why later.

 

Attempt at an ARC solution

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSDictionary *d = (id)dRef;
 4
 5    ...
 6  }

This is roughly what the compile is going to emit (from here on a blue header with the title "Compiler emitted ARC code" means a rough approximation of the generated/emitted ARC code):

Compiler emitted ARC code

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSDictionary *d;
 4    objc_storeStrong(&d, (id)dRef);
 5
 6    ...
 7
 8    objc_release(d);
 9  }

The compiler has to store strongly into d and then release d when it goes out of scope. 

Transferring Ownership

When dRef is created on line 2 it has a retain count of +1. On line 4 it is stored strongly into d which will bump the retain count again (it's a strong reference). So, after line 4 d and dRef, which are the same object, have a retain count of 2. Then at line 8  d is released and the retained count is 1. That means that d and dRef are NEVER deallocated. This code leaks . Sadness ensures.

What happened? Well, d is an Objective-C object so ARC was able to handle it perfectly well. The issue is that dRef, a Core Foundation object, was created but never cleaned up. The solution is super simple.

Attempt at an ARC solution

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSDictionary *d = (id)dRef;
 4    CFRelease(dRef);
 5
 6    ...
 7  }

Now the compiler will insert its calls and the object will be correctly deallocated. This code is semantically correct, but as mentioned above, it doesn't actually compile.

If we look at the code as a whole then we can actually say that lines 3 and 4 represent a transfer of ownership. We had ownership of dRef on line 2 (it had a retain count of +1 with the ownership being this block, lexical scope, or area between the squiggly braces). Then after line 4 we instead have a +1 retain count in d. The ownership of the object has been transferred from CF-land to ARC-land and this pattern is quite common.

Bridging Transfers

ARC introduced a new language feature __bridge_transfer as an ownership qualifier explicitly to be used in casts. Its entire goal was to assist with this pattern. See, I told you it's common enough!

Compiled with ARC (-fobjc-arc)

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSDictionary *d = (__bridge_transfer id)dRef;
 4
 5    ...
 6  }

Now we have a correct solution. This works and does not leak. We use the __bridge_transfer qualifier to tell ARC that when storing dRef into d it should also release dRef so that ownership is properly transferred and there isn't a "dangling retain."

The reason that it didn't compile before is that casting a Core Foundation object, a CFType, to any object (casting to id) is not allowed. In reality CFType is just void* and that's what matters. If you want to cast a void* to an object you need to tell the compiler how to do it. And if what you want is to change from a CFType to an id then what you want is a bridge-transfer and ARC will supply the release for you.

Foundation even includes a function called CFBridgingRelease to perform the same semantic behavior. This gives us a second possible solution. 

 

Compiled with ARC (-fobjc-arc)

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSDictionary *d = CFBridgingRelease(dRef);
 4
 5    ...
 6  }

But don't mistake CFBridgingRelease for anything too cool; it's just the same silly cast under the hood.

Foundation/NSObject.h

 1  NS_INLINE id CFBridgingRelease(CFTypeRef CF_CONSUMED X) {
 2    return  (__bridge_transfer id)X;
 3  }

Bridging Retain

Let's look at another example of code that we want to convert to ARC. 

Compiled with MRR (-fno-objc-arc)

 1  {
 2    NSDictionary *d = [[NSArray alloc] initWithObjectsAndKeys:@"foo", @"bar", nil];
 3    CFDictionaryRef dRef = (CFDictionaryRef)d;
 4
 5    ...
 6
 7    CFRelease(dRef);
 8  }

In MRR this is perfectly valid. After line 2 d has a retain count of +1, then it is cast to dRef and released at the end. But what would happen if we compiled this same code with ARC? Let's look at what the compiler would emit.

Compiler emitted ARC code

 1  {
 2    NSDictionary *d;
 3    $eax = [[NSArray alloc] initWithObjectsAndKeys:@"foo", @"bar", nil]);
 4    objc_storeStrong(&d, $eax);
 5    objc_release($eax);
 6
 7    CFDictionaryRef dRef = (CFDictionaryRef)d;
 8
 9    ...
10
11    CFRelease(dRef);
12    objc_release(d);
13  }

I hope you'll pardon me here for making up some syntax. I am using the temporary variable $eax to store the contents of the array. However I couldn't do this with normal Objective-C because the = operator already has a meaning and I didn't want to use a weak reference because that would be incorrect to the behavior.

What this says is that the compiler allocates the array and after doing the strong assignment, releases it since it is no longer used again in the scope. The ARC optimizer would notice the silliness of this and clean it up slightly to:

Compiler emitted ARC code

 1  {
 2    NSDictionary *d ≡ [[NSDictionary alloc] initWithObjectsAndKeys:@"foo", @"bar", nil]);
 3    CFDictionaryRef dRef = (CFDictionaryRef)d;
 4
 5    ...
 6
 7    CFRelease(dRef);
 8    objc_release(d);
 9  }

where I intend for ≡ to mean "primitive assignment". 

Now it should be obvious that this is an overrelease.  After line 2 d has a retain count of +1. After line 3 both d and dRef have a retain count of +1 and then we release each, meaning that first we release which causes it to deallocate and then we release again. Whoops, crash McGee has arrived!

And you probably guess that the code we are talking about doesn't compile. If you can't cast from a CFType (void*) to an id then why would you be able to go the other way?

So, what we want to do is to tell ARC to retain d on its way into CF. That way we can be good, law-abiding citizens of CF-land and properly release it when we are done (as we have been taught to do an know is correct).  For this we don't want to transfer ownership across the bridge, but to retain the object on its way across. Time for a new qualifier it seems.

Compiled with ARC (-fobjc-arc)

 1  {
 2    NSDictionary *d = [[NSArray alloc] initWithObjectsAndKeys:@"foo", @"bar", nil];
 3    CFDictionaryRef dRef = (__bridge_retained CFDictionaryRef)d;
 4
 5    ...
 6
 7    CFRelease(dRef);
 8  }

and just like last time, we are also provided with a semantically equivalent function

Compiled with ARC (-fobjc-arc)

 1  {
 2    NSDictionary *d = [[NSArray alloc] initWithObjectsAndKeys:@"foo", @"bar", nil];
 3    CFDictionaryRef dRef = (CFDictionaryRef)CFBridgingRetain(d);
 4
 5    ...
 6
 7    CFRelease(dRef);
 8  }

which is nothing more than an inlined function that performs the cast

Foundation/NSObject.h

 1  // After using a CFBridgingRetain on an NSObject, the caller must
 2  // take responsibility for calling CFRelease at an appropriate time.
 3  NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetain(id X) {
 4    return  (__bridge_retained CFTypeRef)X;
 5  }

and even reminds us to clean up after we are done playing with out toys. Thanks! 

Quick Recap:

  • id → CF (retain on the way in) should use __bridge_retained.
  • CF → id (release/transfer on the way in) should use __bridge_transfer.

Casting Just for a Moment

Consider this example. 

 

Attempt at an ARC solution

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSArray *d = @[ @"foo", @"bar", (id)dRef ];
 4
 5    ...
 6
 7    CFRelease(dRef);
 8  }

Surely by now we know that this won't compile! You can't cast a void* to an id! Let's try the one trick we know. 

Attempt at an ARC solution

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSArray *d = @[ @"foo", @"bar", (__bridge_transfer id)dRef ];
 4
 5    ...
 6
 7    CFRelease(dRef);
 8  }

Well shoot. That's an overrelease. We don't actually want ARC to release it. The array can retain it and release it when it it done with it. We just want to convert it to an id without and retains or releases . Please please?

Compiled with ARC (-fobjc-arc)

 1  {
 2    CFDictionaryRef dRef = CFDictionaryCreate(...);
 3    NSArray *d = @[ @"foo", @"bar", (__bridge id)dRef ];
 4
 5    ...
 6
 7    CFRelease(dRef);
 8  }

Note that __bridge is bidirectional. And there we have it, the three bridge casts in all their glory:

  • id → CF (retain on the way in) should use __bridge_retained.
  • CF → id (release/transfer on the way in) should use __bridge_transfer.
  • CF ↔︎ id (no change in ownership)  should use __bridge

Playing With Pointers

Oh yeah, so Objective-C objects are just pointers, right?  This MRR code

Compiled with MRR (-fno-objc-arc)

 1    NSArray *a = [[NSArray alloc] initWithObject:@"foo"];
 2    NSLog(@"The address of a is %p.", a);

will clearly work in ARC, right?  No! You can't cast an object to a pointer (and vice versa) without crossing the bridge! And here we don't want any change in ownership, so __bridge it up.

Compiled with ARC (-fobjc-arc)

 1    NSArray *a = [[NSArray alloc] initWithObject:@"foo"];
 2    NSLog(@"The address of a is %p.", (__bridge void *)a);

Put it in the Pointer, Please

We're almost done. There's only one topic left to address: out variables. That means passing around an id* and setting it explicitly. Well you can actually just declare `id __strong *` or `id __weak *` and the compiler will do exactly what you want when you dereference it for assignment. So, what the issue? I bet you guessed it: void pointers, again!

Imagine the following two silly functions that move src into dest. Have you ever seen anything so contrived? Oh well, it will allow me to illustrate the point. 

Compiled with ARC (-fobjc-arc)

 1  // Store src into dest without retaining it.
 2  void storeArgUnretained(void *dest, id src);
 3
 4  // Store src into dest and retain it.
 5  void storeArgRetained(void *dest, id src);

Let's imagine a simple use of the one that retains the argument during the store. 

Compiled with ARC (-fobjc-arc)

 1  {
 2    id arg = nil;
 3    id src = ...;
 4    getRetainedArg(&arg, src);
 5
 6    ...
 7  }

This works perfectly. The compiler will try to clean up arg and src at the end and that will be fine. The contents of arg with have a +1 retain count because getRetainedArg retains across the store and then the release at the end of scope will decrement and deallocate. Sweet!  But then what about the other one?

Attempt at an ARC solution

 1  {
 2    id arg = nil;
 3    id src = ...;
 4    getUnretainedArg(&arg, src);
 5
 6    ...
 7  }

Well shucks! This one doesn't work. Let's take a look at some pretend emitted code again to try and see why. 

Compiler emitted ARC code

 1  {
 2    id arg, src;
 3    objc_storeStrong(&arg, nil);
 4    objc_storeStrong(&src, ...);
 5
 6    getUnretainedArg(&arg, src);
 7
 8    ...
 8
10    objc_release(arg);
11    objc_release(src);
12  }

The problem is that the storeStrong for arg is storing nil and then we put an argument into the pointer without retaining it. Thus we have a release downstream for an object we never retained. Whoops! That an overrelease if I ever saw one for sure. 

So, we need a way to tell ARC, "don't try to release this object because I am not retaining it!" If we expand this a little more we are actually saying "hey ARC never retain or release this object. I don't want a strong variable. I want an unretained one!"

Oh, weak. That's unretained. Let's use that! Sorry, nope, can't. The problem will actually be the same. The contents of the pointer are assigned without ARC's knowledge. It wouldn't be able to problem bookkeep a weak variable in this case and the self-zeroing wouldn't work. Sadly, if you go behind the compiler's back then your only choice here is to give up a safe, unretained pointer and go with an unsafe, unretained pointer. 

Compiled with ARC (-fobjc-arc)

 1  {
 2    __unsafe_unretained id arg = nil;
 3    id src = ...;
 4    getUnretainedArg(&arg, src);
 5
 6    ...
 7  }

Another common place you'll use/see __unsafe_unretained is for storing object in structs. They don't have any real kind of teardown so proper cleanup is impossible (however in Objective-C++ structs are actually classes and have deconstructors so storing __strong or __weak objects in them is completely fine).

The unfortunate part with the solution above is that now you are using an unsafe reference. It could dangle at any minute! You have to somehow ensure that wherever its contents came from continues to stay alive for as long as you want to use it.

This is the price you pay for flexibility and for using a void*. NSInvocations's getArgument:atIndex:  suffers from this exact problem. It takes a void* because it could stuff anything into it, including a non-object, and so to pay for that flexibility, you have to let things get just a tad unsafe .

BUT if you know that you are only ever going to stuff an object in there and that you don't want to retain it, then you could put in an autoreleased object. The following function will simply do the right thing.

Compiled with ARC (-fobjc-arc)

 1  // Store src into dest and retain-autorelease it.
 2  void storeArgRetainAutoreleased(id __autoreleasing *dest, id src);

Don't forget that id is an object pointer. So id* is an object pointer pointer. This is the exact pattern you will see for the out-variable pattern with NSError. The arg will be `NSError *__autoreleasing *`  and the compiler will make all your dreams come true.

Just in case you want to see how and when these function do and don't crash, here are some simple yet illustrative examples to poke and prod. 

Compiled with ARC (-fobjc-arc)

 1  // Store src into dest without retaining it.
 2  void storeArgUnretained(void *dest, id src) {
 3    *((void **)dest) = (__bridge void *)src;
 4  }
 5
 6  // Store src into dest and retain it.
 7  void storeArgRetained(void *dest, id src) {
 8    *((__strong id *)dest) = src;
 9  }
10
11  // Store src into dest and retain-autorelease it.
12  void storeArgRetainAutoreleased(id __autoreleasing *dest, id src);
13    *dest = src;
14  }

Stop the Snark, Get out of the Dark, and Just Use ARC

At first ARC seems so simple and easy. You don't have to write retain, release, and autorelease; wow. But then you hit the bridging and the address-taking and it gets tricky. Hopefully this helps demystify and provide some depth and intuition to what its doing and how to use it. With time and practice you'll find that it's really not that bad. 

Whenever you find yourself thinking "how can I make the compile emit a retain here and a release there" realize that you are approaching it incorrectly. At some point after the creation of the first compilers people had to stop thinking "how do I get to it produce such and such assembly" and instead use it as intended and accept it as a decrease in burden on the developer, as long as you operate within it. I don't miss MRR one bit.

 

ARC is awesome and I love it. Apple and the clang committers are working hard to keep improving it and it's only going to keep getting better.

 

 

Making it Roar

Problem Solving for Feedback and Growth

There's an old saying: Make it work. Make it right. Make it fast. Crazily enough, I only recently heard this for the first time and have failed to evict its constant repetition from my thought-box. It has an elegant rhythm and bluntness through which I have observed my mind applying without bounds.

It represents a high-level approach for problem solving. Always begin with a solution. It doesn't matter how terrible it is, or how incomplete, just have something. Forget the details, the its (im)purity, and all the details yet to be handled. Find the shortest path possible and just make it work.

When arriving at an idea it is too easy to stop and examine it. The thinking process is then a start-and-stop dance of creativity constantly fighting to avoid any analytical behavior. Find an inkling and inkle it to existence. It's a great chance to actually get a feeling for whether the problem that is being solved has any merit to begin with and if the intended solution bears any weight to stand upon. The sooner you have feedback the sooner you can feed back on it and iterate and improve. The longer you go without feedback the more likely you are to derail and lose focus and the less likely you are to reach the essence of the problem, distracted by the need for a solution.

Once you have a garbage solution and have smelled it long enough to do what you want, you can plug your nose and throw it away. The tightness of the feedback allows you to immediately turn around and apply your understanding and rapidly iterate as the list of bad qualities of the solutions dwindles. Make it robust and fix all edge cases. Then you can ensure the solution will firmly withstand the inherent pounding forces of the problem and that you have reached a solution that can appropriately be labeled “correct.” Take you initial bad solution, iterate, and make it right.

With a good solution in hand, polish and adjust it to fit all the constraints. This is the final step to solving problems. This would be in the vain of make it done; however that is not the final bit to the phrase. The origin actual comes from programming. First write a program that works, then make the way that it is written right. Then the programmers would have to make it efficient and fast. Speed was all that mattered in those days; computer were room-sized behemoths that were slow and had few bells and whistles, literally.

A More Modern Approach

In modern day computers and systems there are many more constraints: memory, battery life, design and attention to detail, speed, and much more. We no longer live in the world of make it fast and I find make it work; make it right; make it fast to sound quite antiquated. The saying needs to be updated. It appears that it has been made to work (it made me write this post) and even seem to have been made right (it’s quite fun to say). But the phrase has not been made to be fast; which doesn't particularly make any sense. The phrase itself needs something else and isn’t speed. It needs a zest of speed and power, design, elegance, and fury. It must dominate, command, and conquer. It must scream. It must roar.

Make it work. Make it right. Make it roar.

Problems are Everywhere

New relationships can be rough. Two people find themselves thrust into long and intense spacial and temporal proximity as every vice and bad habit begins to carve holes in the ship, reducing the ability to float. What can be done to improve the relationship at the start? Do whatever it takes to get along and learn to know each other at ever-increasing depths. Let go of all your rules, strongholds, and assertions of fairness and just do whatever it takes to make it work. Then, as your relationship continues the warts will fall off and imperfections will come to be cherished. You will grow and find the room to fix all issues and take the relationship to the next level. You will find the way to make it right. From there you can travel the world, start a company together, put on a play, relax on the couch on a rainy day, or whatever whims carry you onward. Live, laugh, love, and learn. Enjoy the relationship the had been made to roar.

Need to give a presentation? Throw all the information into a bunch of slides, decide what goes where, and then finally polish it off. Finish with a presentation that truly roars. New project at work? Start with something that barely works and end with it roaring. The process applies to a business plan, designing a poster for a movie, choosing the theme of a party, starting a friendship, handling a disagreement with a coworker, solving a financial dilemma, raising a child, writing a story, and more.

It's an inherent pattern that can be used to solve any problem and one that maximizes tight and powerful feedback as quickly as possible. Arrive at at least one functional solution and then solve it better. End with the solution the sparkles from every angle.

The Greatest Fault

I have to ask myself why this suddenly matters so much to me. And this has led me to understand that my general approach to problems was, and still is, generally backward. I approached every problem: Make it roar. Make it right. Make it work.

The first idea in my head would be to draw the perfect solution, one that was clever, simple, ideal, and ideally magical. When beginning a problem, I had to make it roar. I had to see a solution that I knew was great and that I had from a very high-level solved the problem. Then I would ensure that it covered all cases and was thorough enough to span the whole problem space. At that point I was able to stand up and argue confidently that I understood the solution and could make it right. Finally, I would sit down and implement my solution, covering every last detail, and then lean back knowing that I had made it work.

I've managed well to make it this far with this approach and yet never had any notion that my process was so inherently flawed. The purity of the final solution would block all thought processes, half-assed solutions were verboten, and mediocrity was not acceptable. Yet, in retrospect the real mediocrity was the amount of time that it took to reach a working solution in many cases and then the giant death toll of time when the constraints or problem changed.

Don't Be a Magician

Looking back I see that I have taken the magician's approach. When asked "how is X coming along?" I would always answer confidently, "wonderfully! I'll have something to show you soon." And then I would return to my mind-fortress and continue ironing out the details of the master plan I had underway. Until the details were all solved I actually had nothing to show. And then when it all came together I would appear and say "Tada! Here it is." The code would be clean, the overall architect understandable and there would be little time left. I never felt this was an issue. I have met my deadlines and finished my projects. Perhaps those who were depending on me were nervous. Reflecting back I can hear them saying, “Is there something you can show me?”

My need to have something great upfront meant that I stalled until I had it. Solutions would be thrown out from the beginning with the recognition that one detail was out of place. The amount of time it took to get even the smallest bit working, and thus receiving feedback, was just too long. I may have made my deadlines, but I wasn’t growing.

Problems are Made of Problems - Efficiency Compounds

In most literary works there is a main story arc with the exposition and rising action, the climax and falling action, and finally, the resolution. The story begins with problems and issues and the characters fighting against their environment to survive. The bareness of a plot comes into being and the story just barely stands as something coherent. The issues are conveyed, the plot(s) set in motion and the story is made to work. Then after iteration and evolution the story reaches a pinnacle, the pieces begin to fall into place, and all constraints and problems seem to be solved. Everything is made right. Finally with some surprise and cleverness the story closes with the entire work fully presented and gifted. Your mind spins as the pieces replay in your mind and you realize all the wonderful subtleties and foreshadowing littered across the story’s landscape. You feel the immenseness of the story and if it was done just right, you might even feel it roar. Telling a good story is analogous to solving a problem.

In a the story there is typically a hierarchy of individual story arcs that apply to a character, a group of characters, a particular issue, or any other element that managed to erupt from the author's creativity. The end of a few arcs may actually turn out to only be the initialization of a larger one; there might be a cloud of impending problems where even after fully solving a few, you are only barely starting to make it work. In the process of solving a problem, or telling a story, there are smaller problems that themselves have even smaller problems which repeat downward.

If every subproblem starts with planning (instead of doing) there is inherently going to be number of stalls before some momentum is gathered. This was, and still is, my fundamental flaw. I love to plan.

Incessant Stalling

I need the solution before I attempt to apply it. I encounter a problem and stall. Once I have identified the subproblems I choose one and stall. Then once I have it mapped out, I start at its beginning and stall. It takes most of the problem being solved before I even understand the true problem and any misunderstanding comes out as a massive loss of time and a waste of the chance to grow.

For two weeks I have been pair-programming with Kent Beck, something I am enjoying very much and will post more about soon, and I am so thankful for him saying Make it work; make it right; make it fast and then forcing me to execute it (he made me solve a problem is the fastest way possible and then iterate on the solution) and my eyes feel more open ever since.

Now when I am solving a problem and I find myself falling into planning mode I write down my concerns, shrug them off and keep going. I'd rather buy a shitty car and learn to drive it than spend years saving for a Porsche.

A Framework for the Future

In reality no person and no solution can ever truly be be perfect. I am learning to simplify my solutions and lessen their appearance of perfection. I am learning when and how to stop planning and I am learning when to let go.

When it comes to learning I always aim for a breadth-first approach and yet the manner in which I solve problems has been depth-first all along. The way I learn and the way I do have been at odds all along.

And now that I know this is my largest hindrance I have a problem on my hands. Using sticky notes and cheap concentration tricks I will find a better workflow that just works. Then I can iterate on it until I feel that it is right. And finally after lots of feedback from myself and others I hope to one day find that the way I approach problems is something that truly roars.

Make it work. Make it right. Make it roar.

Learning Breadth-First

Forgoing Every Question Unanswered

My life's philosophy in one word: breadth. Breadth wins arguments, perpetuates learning,  carries conversations, supplies surprise,  enables agility,  increases connection-density of thoughts, and can be obtained in independent and immediate chunks.

Breadth enables and compounds. Depth isolates and narrows.

Information Digestion

Achilles* and the Shark are sitting on a park bench on a radiant day.

Achilles: Do you know why is the sky blue?
Shark: Great question! First, sunlight is actually made of all colors mixed and -
Achilles: Wait, if you mix all the colors you get bright white?
Shark: Yes. We perceive white light when photons of varying wavelengths bombard the receptors in our eyes and -
Achilles: Photons? What are those?
Shark: Little packets of light that are emitted by atoms and -
Achilles: Packets of light? I've never heard of them. What are they like?
Shark: Well, that's a tough question. There are particle, quantum mechanical, optical, electromagnetic, and many more interpretations of them and their behavior. Let's start with -
Achilles: This is why the sky is blue?
Shark: It is indeed! And if you keep listening you'll find the depths of science! Eventually.

In less than a minute Achilles gives up and changes the subject.

The next day, while relaxing with the Tortoise, he decides to ask the same question.

Achilles: Why is the sky blue?
Tortoise: The sky is made of stuff that makes all colors except blue disappear. Might you guess why grass is green?
Achilles: I'd guess because it's made of stuff that makes all colors disappear except green. Is that correct?
Tortoise: Precisely. That is why blood is red, carrots orange, lemons yellow, hamsters golden, and my shell green.
Achilles: So that explains the color of everything. That's pretty cool!
Tortoise: It's not actually true for purple, heh, but that's sideways of your question. I'm glad to answer if you'd enjoy more breadth to your new understanding.

Depth-First Drowning

The Shark  answered none of Achilles' questions and was interrupted in each attempt. The Tortoise, on the other hand, gave a response that empowered Achilles with intuition and the ability to correctly apply the new knowledge.

Given the Shark's answers it should be obvious that he has a deep understanding of Physics. Unfortunately, all of his answers are all depth-centric and try to answer the question based on the concepts of the lower abstraction (the true, derivable answer). This approach to teaching and learning is incredibly flawed; you have not yet learned the lower abstraction and so will attempt to digest it through yet another abstraction lower. Repeat this process and no understanding is attained at any level until each is firmly understood from the very bottom and the learner can reapply the knowledge back up to the top. In reality, this takes forever. One must concede and select a level at with to attain intuition before continuing onward.

In depth-first learning the first question takes the longest to answer.

Assumptions

Recall the Tortoise's answer:

"The sky is made of stuff that makes all colors except blue disappear."

To any learned person this answer should look terrible and sounds childish or perhaps, even ignorant.

  • Why say "the sky is made of stuff" instead of "the atoms in the sky" or simply "the sky" and not distinguish it from its components?
  • Why "all colors except blue disappear" instead of mentioning absorption, scattering, or the source of the colors themselves?
  • Why is "The sky scatters blue light" not just as good, if not a better, answer?

The answer: assumptions.

Each of the above questions try to slip extra words and concepts into the answer, burying the assumption that the questioner knows them. The Tortoise's answer could understood by a child, and I can tell you, from experience, that I have had the Tortoise's conversation with children and they can indeed immediately tell you why grass is green, and without hesitation. I wonder, by chatting with the Shark, how long it would take for a child to have any understanding of why the grass is green. The answer is easy: not until college, or for most people, never.

The argumentative reader may interject, "what if the listener already knows what atoms and scattering are?" Well, a person familiar with atoms and the scattering of light does not ask why the sky is blue, and if he or she does, then clearly atoms and scattering are actually not understood. Though, with the depth-based approach to learning it is quite possible for someone to have some understanding of atoms and scattering and have lost all context of the high-level implications.

What kind of person asks the question why the sky is blue? What might he or she already know? What is the context to the question? And most importantly what will be done with the answer? 

Context trumps assumptions. Context is breadth.

Per-Level Intuition

Looking at Achilles and the Shark it is apparent that every answer is just a waste of time. The conversation quickly dives to the deepest depths of human knowledge with every fragment of understanding thrown out along the way.

For any knowledge-driven dive there are three possibilities:

  • The interrogator gives up
  • The dive hits bottom
  • A forced-stop occurs at a particular depth

The first is the most common and the reason why most conversations beginning with "Why" go unanswered - the answer is simply too complex, meaning full of assumptions and vacuous in context. The second possibility is insane. If the precursor to learning were understanding the lowest known abstraction (currently the standard model of physics) then it can be expected that no one will ever get anywhere. Try to teach a child quantum mechanics before allowing the chance to play with mirrors. It will not work.

That leaves the third possibility, stopping at a particular depth. Choose a level of abstraction and accept it as the basis of everything. But then, why not start at the highest level possible? Learn the implications and intuitions of the highest level of abstraction and then carve downward. This is one way in which current computer science education is a complete failure. Almost always it begins at the very bottom.

Intuition alone is not enough. If you tell someone "the sky makes every color other than blue disappear," the obvious response is that such a statement is the least intuitive idea ever, which is to be expected. If it were intuitive then no one would ever ask about it in the first place!

Intuition comes after that statement, when the inquirer treats it as fact. Given that it is true, via intellectual trust, what more can be ascertained about the world? The dialog above shows that statement providing a sufficient basis for guessing the cause of the color of all objects. The true win is that the conclusion is false. It fails to explain the cause of the color purple, but taking the over-reaching generalization is the first step to improving approximated understanding, instead of forcing the whole picture up front. And now, if anything, your curiosity is sparked to understand why your intuition failed and what is unique about purple.  

When the learner has enough context and breadth of understanding, the words "absorb" and "scatter" will come for free. There will come a point where there is enough intuition on the behavior of light to hear the definition of scattering and accept it simply as a name for a concept already known. That is breadth.

A Breadth-ful Life

How often have you found yourself in a conversation where you feel you have nothing to contribute and you are completely unable to comprehend? Where is your breadth? Where is your ability to pull the conversation, or steer it toward your context and away from their assumptions?

Breadth, and the ability to wield it, will allow you to enter any conversation and the more conversations you can enter, the deeper into each you can go. Breadth is the compounding force of learning. It will allow you to draw patterns across broad areas, helping to win arguments or contribute an idea. You will find yourself often surprised when a new connection forms between two apparent disparate ideas. Where is the surprise in depth? The surprise is at the top and to the sides, where the world appears to be a puzzle where you have to play the game to fit them all together, instead of carving one single piece into the perfect shape.

The more context you have the more free you will be. Agility at your job, potential at another, stories at Christmas, or arguments over coffee. Don't be the depth-er waiting for your moment to come where you inject a rush of depth and knowledge. Be the breadth-er balancing across the entire conversation, learning at some parts and dancing through the rest.

Go to the breadth and soak in it. Enter every conversation with as much context as you can bring, from every subject imaginable. Apply your imagination and the ways in which a raven is like a writing desk becomes infinite.

Breadth-First, Depth-Eventually

A person who grasps physics, chemistry, biology, mathematics, engineering, linguistics, psychology, design, religion, history, literature, and so forth is capable of seeing many more patterns and learning more quickly by integrating information into many already knowns. This increases the intuition gained per new concept. Breadth is implicit context supplied to every new idea. School will not provide you with this, no matter how much it promises. You will gain it from reading, exploring, conversing, teaching, guessing, and from every corner of life and your own creativity.

Go to a random Wikipedia page. How much of the first paragraph do you already understand? How many pages do you have to open, all of which reference one another, to comprehend it? Do you know enough to flatly accept all of the contents and have some form of intuition?

If this sounds difficult and you think it's best to scroll down the page and read the whole thing, then enjoy the depths to which you are diving; the farther down you go, the less of us you'll find. What's the rush to reach depth? You have clearly already forgotten all of the first paragraph. Are you diving or sinking? They both look the same.

Depth should be accidental. When you have enough breadth on a topic you will begin to learn words for the intuitions you already have. Then you will grow breadth, context, and intuition surrounding those words. Eventually all of that new understanding will be identified with more words and you will continue the iteration, learning forever. That is depth as the overflow of breadth, a pain-free route to it. Depth should be free.

Breadth is what you should be fighting for. Eventually you really can and will know everything, because you'll be around people who collectively understand it all and you'll have just enough breadth to always join in the conversation and get just a little more. A breadth-ful conversation will plant the seeds of the depth of the universe. Jump in a conversation. I'll see you there.


"Achilles and the Tortoise" is a reference to Zeno's paradox, the idea that if there are an infinite number of locations between here and there, how can one ever get there?

I'd argue: through breadth.