Advanced Objective-C For Distinguished Gentlepersons

urlDoes the thought of programming Android applications cause your powdered skin to crawl? Do you turn up the volume of the classical music issuing forth from your gramophone in contempt when informed that Objective-C is “clunky and inelegant?”

Then this is the article is for you.

What follows is a gentleman’s exploration of the topics present in only the most dusty corners of iOS and Objective-C which only a true connoisseur will appreciate.

Associated Objects

Associated objects are an interesting oddity made possible by Objective-C’s dynamic nature. In short, you can slap associations onto any NSObject and then summon forth these references at a later period. It is the iOS-equivalent of adding a sticky-note onto something which you can fetch at a later date.

If you ever wish to associate two objects together, you may use the below code (one of several object association methods present in deeper Objective-C) and then provide a “key” (in this case “something”) which you can then use to look up where that association was set previously.

It goes like this:

1
objc_setAssociatedObject(someObject, "something", your_object, OBJC_ASSOCIATION_ASSIGN);

If at some future point, you wish to tunnel through space and time and discover what you have attached to your object, you can use the following line to recall the associated object:

1
objc_getAssociatedObject(your_object, "something");

Swizzle StickSwizzling

Most individuals of higher breeding are familiar with the practice of sipping swizzlers yet may be surprised to learn that the term “swizzling” does not always refer to the practice of upending such a beverage on a street urchin.

Again, due to the dynamic nature of Objective-C, nearly anything can be rearranged during run-time to behave differently.

In this situation, two functions may be swapped for one another. Under the hood, message passing secretly works by resolving selector calls to functions at run-time by looking up the associated function for a class in it’s function table (or dispatch table, basically an array of SEL objects). This function association may be rewired through the clever use of the +load method which is used by categories to do various magical things on run-time.

Here is an example borrowed from the above StackOverflow example being used to rewire a method on a class definition:

+ (void)load {
    SEL originalSelector = @selector(ReceiveMessage:);
    SEL overrideSelector = @selector(replacementReceiveMessage:);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method overrideMethod = class_getInstanceMethod(self, overrideSelector);
    if (class_addMethod(self, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
            class_replaceMethod(self, overrideSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
            method_exchangeImplementations(originalMethod, overrideMethod);
    }
}

Huzzah, our method has now been swizzled.

A Gentleman Never #defines

As a final note, I wanted to mention that the #define keyword has become frowned upon by those with advanced Objective-C understanding.

The reason is simple: #define (a macro which is automatically replaced on compile) does not come with the benefits of type-safety.

Instead, using static const defines is generally preferable in the “.m” file of your classes as opposed to the “.h” file.

So in your .m files for static private variables favor this form. It is important to note that “static” effectively means “private” in Objective-C which is very different than it’s meaning in Java (global).

1
static const NSString *UXRYourVariable = @"derp";

If you would like to create a global variable using this form without falling back on the #define macro, do this in your “.h” file. Here is a great link on the topic.

1
extern NSString* const USPYourNotificationName;

and in your “.m” file:

1
NSString *USPYourNotificationName = @"derp";

The extern keyword indicates that this symbol is to appear in the global lookup table.