Nevertheless, these constraints prevent us from writing our code exactly as we might think about it. What meaningful metaprogramming can we do with those constraints in place? As we'll see, even with the compiler checking us, there’s lots of accessible metaprogramming, ranging from stuff you’re already using to more complex patterns that help you write shorter and more robust code.

A side note on Swift

Before we move on to practical metaprogramming in Objective-C, it's worth discussing Apple's new language, Swift. Swift is still quite immature, and doesn't have many constructs for metaprogramming. Its compiler is more strict in some ways, preventing us from taking some of the liberties that we can in Objective-C, but it does have a top-level function called reflect that will retrieve the properties of an object. As the language matures, we will certainly see more metaprogramming capabilities. So, on to metaprogramming in Objective-C:

Metaprogramming is already commonplace

Have you ever needed to get a weak reference to self for usage in a block?

__weak RGSongViewController *weakSelf = self;

Later, in refactoring, you move this code to another class, and you realize that this line of code implicitly couples itself to the class it's inside of.

You remember a snippet of code you found in AFNetworking that dynamically grabs the the type information the object instead of having it be hard-coded:

__weak __typeof(self) weakSelf = self;

Instead of explicitly telling the compiler what the type of weakSelf is, you're saying “I don't care, just use whatever the type of self is”. This code is no longer bound to the class it was originally written in. In fact, we can further tighten up the abstraction by using the @weakify and @strongify macros from libextobjc framework.

This is metaprogramming! It doesn’t have to be complicated.

Key-Value Lime Pie

Metaprogramming is abundant, even in Cocoa and Foundation, the Apple-provided frameworks. Cocoa has facilities for using keys to change and observe values of objects, called Key-Value Coding (KVC) and Key-Value Observing (KVO), respectively. These might look like simple APIs, but under the hood, they manipulate the runtime in complex ways to accomplish their tasks.

Key-Value Observing is another form of metaprogramming built right into Cocoa. Instead of using it to set and get values, you can use it to be notified when one of those values changes. This is valuable for getting highly specific updates in your controller when your model changes. KVO might just seem like a normal Cocoa API, but, behind the scenes, that class is being replaced (during runtime!) with a duplicate of the class that has code injected into the key's setter to dynamically call the observing object back. Metaprogramming at its finest, and we all use it every day without even blinking.

Look Within

Of course, we can't observe or change the keys on a model if we don't know what keys exist on a model. For this, we rely on introspection. Introspection allows you to peer into any object and see what properties and methods it has available. To talk to your classes and get this information, you can use a weird-looking C function: class_copyPropertyList(className, *count). It’s pretty easily abstracted behind some Objective-C. This function returns a struct which includes attributes of that property, like such as weak, readonly, its class, and so on.

Once we have access to the properties of a model object, we can do object mapping trivially. After retrieving JSON from, say, a server, we can grab the properties of our model object and iterate through them to check if we have a value for it in the JSON dictionary. And, since class_copyPropertyList gives us attributes like the class of each property, we can initialize the correct object for nested properties as well. And of course, those new values are applied to the object using KVC! Because we got the names of the keys from the object itself, we know that those keys are certain to exist on the object. Each of these metaprogramming techniques is awesome by itself, but when they come together, that’s when we can create something amazing.

@dynamic @properties

In Objective-C, you can use an @property declaration to define some property on an object and instance variables to back it.

@property (nonatomic, strong) NSString *name;

Before LLVM 4.0, you would use the directive @synthesize name = _name to generate the instance variable _name, a setter - (void)setName:(NSString *)name, and a getter -(NSString *)name.

@synthesize is now implicit, but it has an explicit counterpart — the @dynamic directive. @dynamic tells the compiler “Don't generate anything for this property, I will catch it and handle it dynamically”. Once you declare a property as @dynamic, you need a backing store for your properties, and some +resolveInstanceMethod: magic:

-(NSMutableDictionary*)backingStore{if(!_backingStore){self.backingStore=[NSMutableDictionarydictionary];}return_backingStore;}+(BOOL)resolveInstanceMethod:(SEL)sel{NSString*selectorName=[NSStringFromSelector(sel)lowercaseString];NSString*key=selectorName;if([keyhasPrefix:@"set"]){key=[keysubstringWithRange:NSMakeRange(3,key.length-4)];//trim the "set" and the colonIMPimplementation=imp_implementationWithBlock((id)^(RGSong*self,idarg1){return[self.backingStoresetObject:arg1forKey:key];});class_addMethod(self,sel,implementation,"v@:@");returnYES;}else{IMPimplementation=imp_implementationWithBlock((id)^(RGSong*self){return[self.backingStoreobjectForKey:key];});class_addMethod(self,sel,implementation,"@@:");returnYES;}return[superresolveInstanceMethod:sel];}

Dynamic Message Construction

Rails's dynamic finders (such as +findWhereTitleEquals:, discussed in the previous article) are an example of dynamic method resolution, where we send a method with a signature that is defined by the sender but not the receiver. The receiver then receives that message, and resolves it into an actual implementation. Using this in Objective-C isn't very realistic, because you would have to turn off ARC and compiler warnings, since the compiler will check for the declaration of methods in the class's header file and the existence of an implementation for that method.

What is possible and very effective is dynamic message construction, which involves sending a message dynamically to an implementation that already exists. You can see dynamic message construction at play in Core Data's validators. Core Data will dynamically check for and call methods of the form validate<Key>:error:. For example, if you had a name property, all you have to do is implement -(BOOL)validateName:(id *)ioValue error:(NSError **)outError, and Core Data will dynamically call it. This could all be rolled up into one big method called -validateValue:forKey:withError:, but it's certainly a lot less elegant.

For example, in the Genius app, we use -configureCell:atIndexPath: when setting up cells to break the creation of the cell apart from its configuration. If a table view has lots of types of objects represented in its rows, we want to break down the configuration method even further:

This is defined on a generic table view controller class, and subclasses only have to implement -configureCell:withSong:. It's called automatically!

The value of this technique shows itself as your codebase matures. You no longer have to update a giant chunk of if-else code, you can just implement the configuration methods that you need.

Between simple macros, KVO, introspection, and dynamic message construction, we can see that metaprogramming in Objective-C isn't impossible and isn’t scary. In fact, you’re already using some of it without even realizing it. These techniques are just the beginning, though. Metaprogramming is just like programming. It’s limited only by your imagination!

Caution: You are now annotating this text as

Edit the description to add:

Historical context: how the event or text affects the world and history

An explanation of the work's overall story (example: "Here, President Obama confirms the legality of drone strikes...")

What is this?

The Genius annotation is the work of the Genius Editorial project. Our editors and contributors collaborate to create the most interesting and informative explanation of any line of text. It’s also a work in progress, so leave a suggestion if this or any annotation is missing something.

Even though Objective-C has a compiler which prevents a lot of abstract metaprogramming from happening, we can still work within the constraints we’ve created for ourselves to create highly leveraged code. This article teaches you how.