Dustin Bachrach

mobile engineer / developer platform enthusiast / dog lover

OCUDL in Depth

Note: I have updated OCUDL to not rely on method swizzling. Please see the OCUDL World Ready section for more details.

Your UI designer is throwing hex values at you. “Update that button’s foreground color to #EEE000.” Or “that background should be #A23111 not #B23111.” This happens repeatedly. So now, everytime, you get to wrestle that hex value into:

+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;

We’re going from this concise, readable, and universally agreed upon syntax, #FFF123, and turning it into:

1
2
3
4
UIColor *myColor = [UIColor colorWithRed:255.0f
                                    blue:(241.0f / 2555.0f)
                                   green:(35.0f / 255.0f)
                                   alpha:1.0f];

Unfortunately, there’s no great way to clean this up. There are macros, which accept a hex value and spit out the above code. You could even go as far as extending UIColor via a category, adding a colorWithHex: helper.

If only our language let us express something like:

1
UIColor *myColor = #FFF123;

There is some precedence of this throughout Objective-C. For instance, you can make an NSString from @"abc", or an NSNumber from @12, or even an NSArray from @[@1, @2, @3]. There’s even precedence in other languages like C++, which have user defined literals today.

These Objective-C literals are baked into the compiler. If we want to get a UIColor literal like these ones, we’d need to go to the compiler writers. Let’s try to avoid that and build a user defined literal system for Objective-C based entirely on what exists today— no change to the language and no change to the runtime.

This blog post explores the in-depth process of creating this system. To get a quick overview and see it in action, take a look at Introducing OCUDL. This project’s source is available on GitHub.

OCUDL

OCUDL, Objective-C User Defined Literals, will allow us to create arbitrary literals associated with any class.

Imagine a class that will measure bytes and indicate whether it’s too large for the system memory:

1
2
3
4
5
6
@interface MyBytes : NSObject {
    NSInteger bytes;
}

- (BOOL)isTooLarge;
@end

When we are working with MyBytes object, it would be convenient to refer to them like:

1
[55b isTooLarge] // 55 bytes

We need to tell our system that any time it sees a literal that ends with a b, it should actually create a MyBytes object.

Literal constructors

A user defined literal can either be a prefix (the # in #FFF123) or a suffix (the b in 55b). When our system recognizes a prefix or suffix, it will instantiate an associated class and pass along the literal (FFF123 or 55, respectively). The class should conform to the OCUDLClass protocol, so it can be instantiated with the literal:

1
2
3
4
5
6
7
@protocol OCUDLClass <NSObject>

@optional
- (id)initWithLiteral:(NSString*)literal prefix:(NSString*)prefix;
- (id)initWithLiteral:(NSString*)literal suffix:(NSString*)suffix;

@end

We can update the MyBytes class to conform to the OCUDLClass protocol:

1
@interface MyBytes : NSObject <OCUDLClass> {

And implement the -initWithLiteral:suffix: constructor:

1
2
3
4
5
6
7
8
9
10
11
@implementation MyBytes

- (id)initWithLiteral:(NSString*)literal suffix:(NSString*)suffix
{
    if (self = [super init]) {
        bytes = [literal integerValue];
    }
    return self;
}

@end

OCUDLManager

We need a manager object that will handle all of these user defined literal registrations.

1
2
3
4
5
6
7
8
9
10
11
@interface OCUDLManager : NSObject

@property (strong, nonatomic) NSMutableDictionary *prefixMapping;
@property (strong, nonatomic) NSMutableDictionary *suffixMapping;

+ (instancetype)defaultManager;

- (void)registerPrefix:(NSString*)prefix forClass:(Class<OCUDLClass>)class;
- (void)registerSuffix:(NSString*)suffix forClass:(Class<OCUDLClass>)class;

@end

The implementation of OCUDLManager is fairly simple. We make it a singleton, which can be accessed via +defaultManager.

1
2
3
4
5
6
7
8
9
10
11
12
13
@implementation OCUDLManager

static dispatch_once_t s_pred;
static OCUDLManager *s_manager = nil;

+ (instancetype)defaultManager
{
    dispatch_once(&s_pred, ^{
        s_manager = [[OCUDLManager alloc] init];
    });

    return s_manager;
}

On initialization, we set up the prefix and suffix mapping dictionaries.

1
2
3
4
5
6
7
8
9
- (id)init
{
    if (self = [super init])
    {
        self.prefixMapping = [[NSMutableDictionary alloc] init];
        self.suffixMapping = [[NSMutableDictionary alloc] init];
    }
    return self;
}

Both registerPrefix:forClass and registerSuffix:forClass map the prefix and class into the manager’s dictionaries.

1
2
3
4
5
6
7
8
9
10
11
- (void)registerPrefix:(NSString*)prefix forClass:(Class<OCUDLClass>)class
{
    self.prefixMapping[prefix] = class;
}

- (void)registerSuffix:(NSString*)suffix forClass:(Class<OCUDLClass>)class
{
    self.suffixMapping[suffix] = class;
}

@end

Registering MyBytes

The MyBytes class can register with the manager to correlate the b suffix with itself.

1
2
3
4
5
6
7
8
9
10
@implementation MyBytes

static NSString* const ByteLiteral = @"b";

+ (void)load
{
    [[OCUDLManager defaultManager] registerSuffix:ByteLiteral forClass:[MyBytes class]];
}

@end

The +load method is called only once when a class or category is loaded into the runtime. This is the perfect time to register the MyBytes user defined literal.

A caveat

So far, so good. We have a lot of the infrastructure for user defined literals. We have an example class, MyBytes, which registers a suffix and a class with our manager. The manager stores a dictionary of all prefix/suffix and class pairs. But we still need a way to go from seeing 55b and calling [[MyBytes alloc] initWithLiteral:suffix:]. How do we do that?

Well, we can’t. There’s no way to hook into what the compiler does when it parses 55b.

We need to adjust our literal syntax just slightly. How about @"55b"? Unlike 55b, this will at least compile because it’s just a string. Now we can just hook into the initialization method that the compiler calls when it sees @"55b".

Oh, wait. NSString literals are special.

You may have noticed that you don’t need to retain and release NSString literals like you do other objects (although it’s still a good idea to do so just out of habit). In fact, you can release them as many times as you want and it won’t do anything. This is because NSString literals aren’t dynamically allocated like most Objective-C objects. Instead, they’re allocated at compile time as a part of your binary, and live for the lifetime of your process.

So NSString literals are not going to suffice. They are compiled into the binary and don’t behave like normal Objective-C classes.

Don’t fret. Along with all of those cool literals for NSArray and NSNumber that Apple added recently, they also added boxed C String literals.

1
@("55b")

It looks very similar to NSString literals, but it behaves differently. Boxed C String literals are dynamically allocated. This gives us a chance to hook into the allocation flow and work our magic.

But to do that magic, we need to dive into the dark waters of method swizzling.

Swizzling up a literal

1
2
3
4
5
6
7
8
9
#import <objc/runtime.h>
#import <objc/message.h>

void Swizzle(Class c, SEL orig, SEL new)
{
    Method origMethod = class_getClassMethod(c, orig);
    Method newMethod = class_getClassMethod(c, new);
    method_exchangeImplementations(origMethod, newMethod);
}

Take a look at that for a second. You may not have seen code like this before. These are actually C functions that form the underpinnings of the Objective-C runtime. Our Swizzle() function takes a Class and two selectors to class methods. We can use this wildly amazing method_exchangeImplementations() function to swap the implementations of these two methods.

So if I have a class with two class methods +foo and +bar, which I’ve swizzled. When I call +foo, the implementation of +bar is invoked. When I call +bar, the implementation of +foo is invoked.

Why the hell would you want to do that?

Imagine we want to override an existing class’ function with custom behavior. But in some cases, we don’t want custom behavior; we actually want to call back into the original behavior. Exchanging the method implementations allows us to swap in our custom behavior and then fall back onto the original one if we want to.

When a boxed C String literal gets evaluated at runtime it calls [NSString stringWithUTF8String:]. We are going to swizzle our own implementation of that in its place. We’ll check if the string that’s being created has one of our registered prefixes or suffixes. If it does, we’ll instantiate the associated class instead. If the string being created does not match our prefixes or suffixes, then we will just fall back on the original NSString implementation of stringWithUTF8String:.

We add a category method to NSString that will implement our custom behavior.

1
2
3
4
5
@interface NSString (OCUDL)

+ (instancetype)ocudlStringWithUTF8String:(const char *)nullTerminatedCString;

@end

We then swizzle it when our category gets loaded into the runtime.

1
2
3
4
5
6
7
8
@implementation NSString (OCUDL)

+ (void)load
{
    Swizzle([NSString class],
            @selector(stringWithUTF8String:),
            @selector(ocudlStringWithUTF8String:));
}

And we implement ocudlStringWithUTF8String:.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
+ (id)ocudlStringWithUTF8String:(const char *)nullTerminatedCString
{

    // Call through original stringWithUTF8String: implementation
    NSString *str = [NSString ocudlStringWithUTF8String:nullTerminatedCString];

    NSMutableDictionary *prefixMapping = [OCUDLManager defaultManager].prefixMapping;

    for (NSString *prefix in prefixMapping) {
        if ([str hasPrefix:prefix]) {
            str = [str substringFromIndex:[prefix length]];

            Class class = prefixMapping[prefix];
            id<OCUDLClass> literalClass = [class alloc];
            return (id)[literalClass initWithLiteral:str prefix:prefix];
        }
    }

    /* Handle suffixes ... */

    return str;
}

We first call through to the original stringWithUTF8String: implementation. We then search through each prefix we have registered and see if the current string has that prefix. If it does, then we instantiate the class associated with it. We would then do the same for suffixes.

Macro cleanup

At this point we have a working implementation of user defined literals. But to use them you have to do:

1
[(id)@("55b") isTooLarge];

Since a boxed C String will return an NSString, the compiler is going to complain about not finding an isTooLarge method. We can cast the result of our literal to id, to let the compiler know we are aware of our hacky approach.

@("55b") also looks more like a string than a literal. We can clean all of this up and make it look more like a literal with a macro.

1
#define $(literal) ( (id) ( @(#literal) ) )

In the macro definition, we can use the # operator to stringify the argument. For example:

1
2
3
#define STRING_IT(arg) #arg

STRING_IT(abc); // -> "abc", cool huh?

With our $ macro defined, we can simply use one of our user defined literals:

1
[$(55b) isTooLarge];

The power of blocks

Our implementation, so far, works best for associating a prefix or suffix with a class you own. We could make a user defined literal for UIColor, but we need to start adding categories on UIColor to implement -initWithLiteral:prefix:.

Let’s simplify this with blocks. We’ll add block versions of our registration methods on OCUDLManager.

1
2
- (void)registerPrefix:(NSString*)prefix forBlock:(OCUDLBlock)block;
- (void)registerSuffix:(NSString*)suffix forBlock:(OCUDLBlock)block;

OCUDLBlock is just a typedef for our block:

1
2
3
4
5
6
/**
 * Invoked when a user defined literal should be created.
 * The first parameter is the literal.
 * The second parameter is the prefix/suffix.
 */
typedef id (^OCUDLBlock)(NSString*, NSString*);

We can implement them identically to the Class version and just save the block into the prefix/suffix dictionary.

1
2
3
4
5
6
7
8
9
- (void)registerPrefix:(NSString*)prefix forBlock:(OCUDLBlock)block
{
    self.prefixMapping[prefix] = block;
}

- (void)registerSuffix:(NSString*)suffix forBlock:(OCUDLBlock)block
{
    self.suffixMapping[suffix] = block;
}

To finish support for blocks, we need to update ocudlStringWithUTF8String:.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for (NSString *prefix in prefixMapping) {
    if ([str hasPrefix:prefix]) {
        str = [str substringFromIndex:[prefix length]];

        id mapping = prefixMapping[prefix];

        if (class_isMetaClass(object_getClass(mapping))) {
            Class class = mapping;
            id<OCUDLClass> literalClass = [class alloc];
            return (id)[literalClass initWithLiteral:str prefix:prefix];
        }
        else if ([mapping isKindOfClass:NSClassFromString(@"NSBlock")]) {
            OCUDLBlock block = mapping;
            return block(str, prefix);
        }
    }
}

When we find a matching prefix, we extract the value out of the prefix map for that prefix. It can either be a Class or a block. Testing whether an object is a block or a Class is interesting. To test for a class you use:

1
class_isMetaClass(object_getClass(mapping))

The type Class, itself can respond to object_getClass(), and returns a special type of class called a Meta Class. The Objective-C runtime has a class_isMetaClass() function specifically for testing if a value is a meta class.

To test if an object is a block we can use NSObject’s isKindOfClass:, but to get a Class for a block, we need to use NSClassFromString(@"NSBlock").

Once we know, the registration was for a block, we can invoke the block directly.

We now fully support block based user defined literals. Let’s try one out. We’ll create a .xib suffix, which will create an UINib for a literal.

1
2
3
4
[[OCUDLManager defaultManager] registerSuffix:@".xib"
                                     forBlock:^id(NSString *literal, NSString *prefix) {
     return [UINib nibWithNibName:literal bundle:nil];
 }];

Multiple suffixes

Let’s expand MyBytes to support a few more suffixes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
static NSString* const ByteLiteral = @"b";
static NSString* const KiloByteLiteral = @"kb";
static NSString* const MegaByteLiteral = @"mb";

+ (void)load
{
    [[OCUDLManager defaultManager] registerSuffix:ByteLiteral forClass:[MyBytes class]];
    [[OCUDLManager defaultManager] registerSuffix:KiloByteLiteral forClass:[MyBytes class]];
    [[OCUDLManager defaultManager] registerSuffix:MegaByteLiteral forClass:[MyBytes class]];
}

- (id)initWithLiteral:(NSString*)literal suffix:(NSString*)suffix
{
    if (self = [super init]) {
        NSInteger value = [literal integerValue];

        NSDictionary* byteMultipliers = @{ ByteLiteral : @1,
                                           KiloByteLiteral : @1000,
                                           MegaByteLiteral : @1000000 };

        NSNumber* multiplier = byteMultipliers[suffix];
        if (multiplier)
        {
            bytes = value * [multiplier integerValue];
        }
        else
        {
            bytes = 0;
        }
    }
    return self;
}

I now should be able to create kilobyte and megabyte literals:

1
2
3
[$(4kb) isTooLarge];
[$(6kb) isTooLarge];
[$(3mb) isTooLarge];

Unfortunately, we have a minor issue in our suffix searching. We find the first suffix that matches, and in this case the b suffix is found before the kb suffix is found. We can fix up our ocudlStringWithUTF8String: method easily by searching through longer suffixes before shorter ones:

1
2
3
4
5
6
7
8
NSMutableDictionary *suffixMapping = [OCUDLManager defaultManager].suffixMapping;
NSArray *sortedSuffixMappingKeys = [[suffixMapping allKeys] sortedArrayUsingComparator:
    ^NSComparisonResult(id obj1, id obj2) {
    return[@([obj2 length]) compare:@([obj1 length])];
}];

for (NSString *suffix in sortedSuffixMappingKeys) {
    // ...

It’s also important to note that OCUDL can only have one class or block associated with a prefix/suffix. You cannot register a prefix/suffix more than once.

Unintended literals

Lots of code calls into stringWithUTF8String: not intending to use user defined literals at all. You can set a breakpoint in ocudlStringWithUTF8String: just to see how much framework and system code is going through there. If, by chance, the system is creating a string that happens to have a suffix you registered, then suddenly things will start to go crazy very quickly.

We need a way to easily know that the string passed into ocudlStringWithUTF8String: was intended to be a user defined literal.

Let’s prefix all user defined literal strings with a well known identifier, so our system can definitively tell if a string that was passed in is a user defined literal.

We’ll use a UUID as the identifier. We can create one easily in the Terminal by using the uuidgen command. We can then update the $ macro to include our well known UUID before the literal.

1
#define $(literal) ( (id) ( @("9AD499E3-61B8-43AC-83A1-4B322E67C9B3" #literal) ) )

This uses a nice C trick to concatenate string literals:

1
char* str = "xyz" "abc"; // str = "xyzabc"

We can then modify ocudlStringWithUTF8String: to check for our prefix.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
+ (id)ocudlStringWithUTF8String:(const char *)nullTerminatedCString
{

    // Call through original stringWithUTF8String: implementation
    NSString *str = [NSString ocudlStringWithUTF8String:nullTerminatedCString];

    NSString *ocudlUuid = @"9AD499E3-61B8-43AC-83A1-4B322E67C9B3";
    if ([str hasPrefix:ocudlUuid])
    {
        // Only treat as a user defined literal if has UUID as a prefix
        // ...
    }

    return str;
}

Back to UIColor

With our user defined literal system complete, we can now return to creating a literal for UIColor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[[OCUDLManager defaultManager] registerPrefix:@"#"
 forBlock:^id(NSString *literal, NSString *prefix) {
     unsigned int value = 0;
     if ([[NSScanner scannerWithString:literal] scanHexInt:&value])
     {
         if (literal.length == 6)
         {
             // 6 digit hex (#FFFFFF)
             return [UIColor colorWithRed:((float)((value & 0xFF0000) >> 16)) / 255.0
                                    green:((float)((value & 0x00FF00) >> 8)) / 255.0
                                     blue:((float)(value & 0x0000FF)) / 255.0
                                    alpha:1.0];
         }
         else if (literal.length == 3)
         {
             // 3 digit hex (#FFF)
             return [UIColor colorWithRed:((float)((value & 0xF00) >> 8)) / 15.0
                                    green:((float)((value & 0x0F0) >> 4)) / 15.0
                                     blue:((float)(value & 0x00F)) / 15.0
                                    alpha:1.0];
         }
     }
     else
     {
         // Color names (#black)
         if ([literal caseInsensitiveCompare:@"black"] == NSOrderedSame)
         {
             return [UIColor blackColor];
         }
         // Check for all the other UIColor default color names
         // ...
     }
     return nil;
}];

A different approach

If method swizzling makes you weary, we could avoid it and get a slightly more verbose user defined literal. Instead of creating our literal’s class when the boxed C string is created, we could hang a property off of an NSString category and do the literal evaluation there.

1
[@"55b".e isTooLarge];

Here, we’ve just created an NSString literal as usual and called through to an e property which evaluates the NSString as if it were a user defined literal and returns a MyBytes object.

This certainly avoids the runtime fudging, but at the price of readability.

Downsides

OCUDL is an experiment and has some downsides. I’m personally, hesitant to swizzle an often used method like stringWithUTF8String:. There may be a performance impact for doing so, or potential conflicts. I even ran into weird behavior where my unit test project did not swizzle the method correctly. I think the unit tests are bootstrapped differently, and the runtime swizzling did not take effect there. I ended up moving the swizzling from +load to initialization of the OCUDLManager to work around this issue.

There are a few usability issues too. When using these literals, the compiler is unaware of the types, so code completion won’t work. Also, since the compiler is unaware of what we’re doing, we can’t create a literal like $(http://apple.com), because the // are parsed as comments.

As long as you understand what’s going on under the hood, none of these downsides are too prohibitive.

OCUDL – World Ready

UPDATE: I originally created OCUDL as a fun experiment to see how close I could get to C++’s user-defined literals. I really liked the boxed C string approach and in the end couldn’t get that to a concise notation. So I wrapped it in a $ macro and that was that. A few people (@percysnoodle, @hypercrypt, and others) commented that since I was using a macro already, we could bypass boxed C strings and method swizzling. Instead we can just define:

1
#define $(literal) [[OCUDLManager defaultManager] objectForLiteralString:@"" #literal]

This directly instantiates an object for a literal string. It’s certainly less “cool”, but it’s functional, practical, and safe for production.

Although OCUDL started as an academic exploration, I think it’s best to switch implementations. The latest source on GitHub has been updated making OCUDL “world ready”. No more swizzling, no more runtime hacking.

Wrap up

OCUDL is a fun exercise in exploring the Objective-C runtime. It’s a testament to the dynamism of the language that we could even get this far. We got to explore some interesting parts of the Objective-C language, runtime, and even a few C tricks. I hope this look into creating OCUDL taught you a few new things. I certainly learned a lot. If you have any feedback or input, feel free to get in touch.