About the Builder Pattern in Objective‑C

Posted on May 25, 2013

When dealing with complex object creation in an iOS application you may feel the need for a cleaner and more fluent approach.

During my latest development my colleague @alexiskinsella set up a pattern based on providers in order to mimic the factory behaviour we often find in languages such as Java.

Recently, in the occasion of a side project, I am studying a slightly different approach, based on this article by Matthias Wessendorf.

What I am willing to do is an image builder which creates UIImages on which a GPUImageFilter is applied.

The result I came to is as follows:

The Builder itself (implementation)

+ (SMFilteredImageBuilder *)builderWithConfigurationBlock:(FilteredImageConfigurationBlock)configBlock
{
    return [[self alloc] initWithConfigurationBlock:configBlock];
}

- (id)initWithConfigurationBlock:(FilteredImageConfigurationBlock)configBlock
{
    if (self = [super init]) {
        self.configuration = [SMFilteredImageConfiguration configuration];
        if (configBlock) {
            configBlock(self.configuration);
        }
    }

    return self;
}

- (UIImage *)build
{
    [self.configuration.imagePicture processImage];
    return [self.configuration.filter imageFromCurrentlyProcessedOutput];
}

The Configuration object (header)

@interface SMFilteredImageConfiguration : NSObject

@property GPUImageFilter *filter;
@property GPUImagePicture *imagePicture;

+ (instancetype)configuration;

@end

 Using a Builder with an inline Configuration

- (void)saveFilteredImage:(UIImage *)image
{
    SMFilteredImageBuilder *imageBuilder = [SMFilteredImageBuilder builderWithConfigurationBlock:^(SMFilteredImageConfiguration *configuration){
        GPUImagePicture *sourceImagePicture = [[GPUImagePicture alloc] initWithImage:image];
        configuration.filter = [GPUImageFilter filterForSquaredImageFromImagePicture:sourceImagePicture withSide:100.0];
        configuration.imagePicture = sourceImagePicture;
    }];

    UIImage *filteredImage = [imageBuilder build];
    [filteredImage saveToDocumentsFolderWithName:@"Filtered.png"];
}

This should make for a quite readable code with a reduced number of lines of code in the method that invokes the builder.