Builder pattern in Objective-C

1 November 2011

Over the past few months I’ve spent a fair bit of time on a project using my MacBook Pro for development. This got me to run CCMenu again and, perhaps predictably, made me work on that in the evenings. While doing some long overdue refactorings I came across the need to construct domain objects in unit tests. So far I had used simple helper methods in the unit test itself, but the Java/Scala project I was on during the day made heavy use of the Builder pattern with fluent interfaces, and that got me thinking.

In the end I’ve come up with three variations of the Builder pattern in Objective-C, all of which have their pros and cons. In this post I want to show these patterns and invite comments on which one you prefer.

Before going into the detail, though, let’s agree on what we’re trying to build. It doesn’t really matter, so let’s pick cars, with properties such as make and model, plus the name of the current owner. To make it a bit harder, let’s make the make and model properties immutable. The interface looks like this:

@interface Car
{
    NSString *model;
    NSString *make;
    NSString *owner;
}
 
- (id)initWithMake:(NSString *)aMake andModel:(NSString *)aModel;
 
- (NSString *)make;
- (NSString *)model;
 
- (void)setOwner:(NSString *)anOwner; 
- (NSString *)owner;
 
@end

Classic Java style

A direct translation of the classic Java builder pattern would give us a class something like the following. Note that the builder provides defaults for the values in case they are not set.

@interface CarBuilder
{
    NSString *make;
    NSString *model;
    NSMutableDictionary *properties;
}
 
- (CarBuilder *)withMake:(NSString *)aMake;
- (CarBuilder *)withModel:(NSString *)aModel;
- (CarBuilder *)withOwner:(NSString *)anOwner;  
 
- (Car *)build;
 
@end
@implementation CarBuilder
 
- (id)init
{
    [super init];                                                                        
    model = @"VW";
    make = @"Golf";
    properties = [[NSMutableDictionary dictionaryWithObjectsAndKeys:@"Fred", @"owner", nil] retain];
    return self;
}
 
- (CarBuilder *)withMake:(NSString *)aMake
{
    make = [aMake retain];
    return self;
}
 
- (CarBuilder *)withModel:(NSString *)aModel
{
    model = [aModel retain];
    return self;
}
 
- (CarBuilder *)withOwner:(NSString *)anOwner
{
    [properties setObject:anOwner forKey:@"owner"];
    return self;
}
 
- (Car *)build
{
    Car *car = [[[Car alloc] initWithMake:make andModel:model] autorelease];
    [car setValuesForKeysWithDictionary:properties];
    return car;
}
 
@end

The usage is straight-forward:

Car *theCar = [[[[builder
                    withModel:@"Beetle"] 
                    withOwner:@"Alice"] 
                    build];

What I like about this approach is its simplicity. What’s not so great is that the calls to the builder are deeply nested. In addition, in the builder we have to declare several variables and, if we cared about not leaking memory in tests, we’d have to add even more code to handle the assignments.

By the way, the use of a dictionary for the mutable properties makes not much sense in this case. It shines once you have more than a couple of properties as it reduces the number of variables and the number of calls in the build method. This is why I’ve shown this little pattern here.

Using categories

Objective-C has categories and that opens up a different possibility for writing builders. Instead of building up the state in a builder object in order to create the real object at the end, we create the object upfront and then set the properties on it, using a category. The code looks like this:

@interface CarBuilder
 
- (id)car;
 
@end
 
@interface Car(BuilderAdditions)
 
- (Car *)withMake:(NSString *)aMake;
- (Car *)withModel:(NSString *)aModel;
- (Car *)withOwner:(NSString *)anOwner;
 
@end
@implementation CarBuilder
 
- (id)car
{
    Car *car = [[[Car alloc] initWithMake:@"VW" andModel:@"Golf"] autorelease];
    [car setOwner:@"Fred"];
    return car;
}
 
@end  
 
@implementation Car(BuilderAdditions)
 
- (Car *)withMake:(NSString *)aMake
{
    make = [aMake retain];
    return self;
}
 
- (Car *)withModel:(NSString *)aModel
{
    model = [aModel retain];
    return self;
}
 
- (Car *)withOwner:(NSString *)anOwner
{
    [self setOwner:anOwner];
    return self;
}
 
@end

The usage is near idential, with the invocation of car at the beginning of the chain replacing the call to build at the end.

Car *theCar = [[[[builder car] 
                    withModel:@"Beetle"]
                    withOwner:@"Alice"];

An advantage of this solution is that the builder class is just one method long and doesn’t grow as we add more properties. In fact, if we don’t care about defaults, this style would work without any builder class at all. We also don’t need duplicate variables for holding on to the values and, lastly, by using category methods the builder code lives inside the object and thus we have more liberty to access and manipulate the internal structures. This can be good and bad, I guess.

Using reflection

Looking for a solution that doesn’t touch the Car class, that avoids deep nesting of method calls during the build, and that scales well with regards to the builder code size in relation to the number of attributes, I turned to reflection.

Starting with the usage, this builder is used as follows:

Car *hotHatch = [builder carWithMake:@"VW" 
                            withModel:@"Golf GTI" 
                            withOwner:@"Bob"];

It is possible to give the properties in different sequences and to leave off properties:

Car *theBeetle = [builder carWithOwner:@"Alice" withModel:@"Beetle"]; 
Car *anyCar = [builder carWithOwner:@"James"];

In fact, the car prefix on the method is syntactic sugar and could be left off, too.

The implementation of this builder is as follows:

@interface CarBuilder
 
/* No methods declared */
 
@end
@implementation CarBuilder
 
- (NSArray *)selectorComponents:(SEL)aSelector
{
    NSArray *components = [NSStringFromSelector(aSelector) componentsSeparatedByString:@":"];
    return [components subarrayWithRange:NSMakeRange(0, [components count] - 1)];
}
 
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    int argCount = [[self selectorComponents:aSelector] count];
    NSAssert(argCount < 100, @"expecting less than 100 arguments");
    char types[105] = "";
    for(int i = 0; i < argCount + 3; i++)
        strcat(types, (i == 2) ? @encode(SEL) : @encode(id));
    return [NSMethodSignature signatureWithObjCTypes:types];
}
 
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSMutableDictionary *values = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"VW", @"make", @"Golf", @"model", @"Fred", @"owner", nil];
    unsigned int index = 2;
    for(NSString *component in [self selectorComponents:[anInvocation selector]])
    {
        NSRange with = [component rangeOfString:@"with" options:NSCaseInsensitiveSearch];
        NSAssert(with.location != NSNotFound, @"excpecting 'with' in selector elements");
        NSString *key = [component substringFromIndex:NSMaxRange(with)];
        id value = nil;
        [anInvocation getArgument:&value atIndex:index++];
        [values setObject:value forKey:key];
    }
 
    Car *car = [[[Car alloc] initWithMake:[values objectForKey:@"make" andModel:[values objectForKey:@"model"] autorelease];               
    [values removeObjectsForKeys:[NSArray arrayWithObjects:@"make", @"model", nil];
    [car setValuesForKeysWithDictionary:properties];
 
    [anInvocation setReturnValue:&car];
}
 
@end

While more complex than the other ones, the implementation is pretty generic and most of the code could be moved into a generic builder base class. It is also fairly short and requires substantially less code to be added for additional properties than the other options.

Sounds perfect? There is one big drawback: the selector changes all the time and usually it would be unreasonable to declare all permutations, which means that Xcode and the compiler show warnings for every use of the builder. If anyone knows how to turn off that warning on a per-file basis…

In summary

The following table summarises the three approaches. What do you think?

Classic Java style Using categories Using reflection
Lines of code 42 33 36
Lines of code per property ~8 * ~6 * 0 **
Advantages Simple Short, internal access Generic, very short
Drawback Lots of code Changes object Compiler warning

* worse if we are strict about memory leaks
** if we break lines for formatting: 1-2

11 comments

  1. Oliver Jones

    1 November 2011, 20:58

    Hi,

    Just a wee point on Objective-C naming conventions/style.

    Don’t do this:

    Car *c = [[Car alloc] initWithMake:make andModel:model];

    do this:

    Car *c = [[Car alloc] initWithMake:make model:model];

    Similarly don’t do this:

    Car *hotHatch = [builder carWithMake:@"VW" withModel:@"Golf GTI" withOwner:@"Bob"];

    Do this:

    Car *hotHatch = [builder carWithMake:@"VW" model:@"Golf GTI" owner:@"Bob"];

    For more information on idiomatic Objective-C naming conventions read these:

    * Apple Coding Guidelines: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.html
    * Matt Gallagher on Objective-C Method Names: http://cocoawithlove.com/2009/06/method-names-in-objective-c.html

  2. Jay Fields

    1 November 2011, 23:54

    Just a note on the builder pattern in general – returning self can lead to some weirdness if you ever create a builder and use it in two different places. To avoid confusion, all of our Java builders always create a new instance of the builder with each call to any “with” method.

  3. Matthias Wessendorf

    30 October 2012, 09:36

    Hey, thanks for the write up – but looks like the “reflection” builder does only work when I disable ARC on my priject – otherwise it does not even compile…

  4. Matthias Wessendorf

    30 October 2012, 10:58

    With ARC enable the ‘reflection builder’ does not compile…

    See https://gist.github.com/3979172

  5. Erik Doernenburg

    30 October 2012, 13:15

    Looks like ARC requires a declaration before it allows calls to a method; hadn’t noticed that before.

    In this case you have to do what I alluded to in the post, you have to provide declarations for some of the possible invocations, e.g.

    @interface CarBuilder(DynamicMethods)

    - (Car *)carWithOwner:(NSString *)owner;
    - (Car *)carWithMake:(NSString *)make withModel:(NSString *)model;
    - (Car *)carWithMake:(NSString *)make withModel:(NSString *)model withOwner:(NSString *)owner;

    @end

    The reason why I’m declaring them in a category is to avoid another compiler issue. If you were to put them into the interface declarion for CarBuilder itself then I’m pretty sure you’d get complaints that some declared methods were not implemented.

  6. Matthias Wessendorf

    3 November 2012, 17:55

    Yes, you have to declare all the functions. If you have a ton of arguments / options to configure this can become nasty. IMO, the non-ARC version was quite nice(r).

    Cheers!
    Matthias

  7. Freddy Wade

    26 May 2013, 19:48

    The builder pattern is great, isn’t it? It lets you create nice immutable classes without the need for multiple constructors and it gives the API users freedom in choosing which arguments they want to use when creating the instance. But what happens when you want to tell the user that she must call one builder method or the other, since it is crucial for the class you’re trying to build? The builder pattern simply doesn’t have such a feature. This post will try to give an alternative solution to this problem.

  8. Get Smart

    24 August 2013, 15:55

    I’m with JohnMunsch, even if your code is valuable, don’t call it builder pattern.The examples on wikipedia are the builder pattern:http://en.wikipedia.org/wiki/Builder_patternIn your code; it is a builder, not a pattern.

  9. Jody I. Rivers

    29 August 2013, 21:47

    The idea behind the builder pattern is to abstract away the construction of an object so that many implementations can use the same builder.

  10. 045 iPhreaks Show – The Masonry Pod with Jonas Budelmann — iPhreaks Show

    6 March 2014, 13:01

    […] Erik Dörnenburg: Builder pattern in Objective-C (Jaim) […]

  11. Programmer Joe

    28 May 2014, 17:03

    I know this an old post but somebody might Have a look at configuration-block technique

    http://www.annema.me/the-builder-pattern-in-objective-c

  12. using a pill to help with sex

    19 September 2014, 09:48

    What you said was actually very logical. But, what about this?
    what if you were to create a killer poxt title? I
    mean, I don’t wish tto tell you how to run yoir blog, but suppose you added a post title that maakes people want more?
    I mean erik dörnenburg

  13. Jose

    19 September 2014, 13:27

    Good dday very nice website!! Guy .. Beautiful .. Wonderful ..
    I’ll bookmark your site aand take the feeds also? I’m satisfied to seek out a lot oof helpful information here within the submit, we
    need work out moree techniques in this regard,
    thank you for sharing. . . . . .

    my blog :: baldness treatment (Jose)

  14. Christine

    20 September 2014, 05:38

    You need targeted traffic to your erik dörnenburg » Articles » Builder pattern in Objective-C website so why not try some for free? There is a VERY POWERFUL and POPULAR company out there who now lets you try their traffic service for 7 days free of charge. I am so glad they opened their traffic system back up to the public! Sign up before it is too late: http://id-vision.be/pcdokter/91

  15. using a pill to help with sex

    20 September 2014, 09:33

    Hey! I know this is kind oof off topic but I was wondering if you knew where I could find a captcha
    plugin for my comment form? I’m using the same blog platform as yours and I’m hsving difficulty finding one?
    Thanks a lot!

    Also visit my wbpage – using a pill to help with sex

  16. Christine

    21 September 2014, 04:29

    You need targeted visitors for your erik dörnenburg » Articles » Builder pattern in Objective-C website so why not try some for free? There is a VERY POWERFUL and POPULAR company out there who now lets you try their website traffic service for 7 days free of charge. I am so glad they opened their traffic system back up to the public! Check it out here: http://mgr.pl/t2v

Leave a comment