Method Chaining in Objective-C and how to make your own

· 2 min read

When I was using the Masonry, I was shocked by author’s thoughts on bring Functional Programming to objective-c, which present a clean and concise way on developing. Normally a chain method looks like:

Method Chaining is simple but powerful, which has three key points, everyone can create his/her own chaining method after knowing this:

To be able to create chain methods in objc, there are some features:

  • Methods can be called consecutively;
  • Each of the method return the same type, in this case is class instance;
  • Special in Objective-C Many other languages can do the same thing as well, as which only allows to use square brackets to call methods. parenthesis is used for block.

Hold those ideas in mind, it is quite nature to think about creating a new class for the Chaining Methods Calculator:

CalculateChain.h


#import <Foundation/Foundation.h>

@interface CalculateChain : NSObject

@property (nonatomic) float result;

@property (readonly, nonatomic, copy) CalculateChain* (^add)(float num);
@property (readonly, nonatomic, copy) CalculateChain* (^minus)(float num);
@property (readonly, nonatomic, copy) CalculateChain* (^multiply)(float num);
@property (readonly, nonatomic, copy) CalculateChain* (^divide)(float num);

/* also you can only expose the getter methods
-(CalculateChain*(^)(float))add;
-(CalculateChain*(^)(float))minus;
-(CalculateChain*(^)(float))multiply;
-(CalculateChain*(^)(float))divide;
 */  
 
@end

CalculateChain.m


#import "CalculateChain.h"

@implementation CalculateChain

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }
    self.result = 0;
    return self;
}


-(CalculateChain*(^)(float))add{
    return ^CalculateChain *(float value){
        _result += value;
        return self;
    };
}


-(CalculateChain*(^)(float))minus{
    return ^CalculateChain *(float value){
        _result -= value;
        return self;
    };
}


-(CalculateChain*(^)(float))multiply{
    return ^CalculateChain *(float value){
        _result *= value;
        return self;
    };
}


-(CalculateChain*(^)(float))divide{
    return ^CalculateChain *(float value){
        if(value!=0)
            _result /= value;
            
        return self;
    };
}

@end

So you can call the calculator methods like:

CalculateChain *calc = [[CalculateChain alloc] init];
calc.add(10).minus(5).multiply(100).divide(2);
NSLog(@"results: %f", calc.result);

Some Improvements (2018):

The above class is enough to use, however it still has some drawbacks:

  • Every time to use, we have to create a new class/class instance
  • A global variable is created to store the final results.
  • Luckily, objective-c provide a extension and category which can help developers to add more functions to existing classes. In our case, all the NSNumber object can have the chaining methods.
// NSNumber+CalculateChain2.h
#import <Foundation/Foundation.h>

@interface NSNumber (CalculateChain2)

-(NSNumber*(^)(float))add;
-(NSNumber*(^)(float))minus;
-(NSNumber*(^)(float))multiply;
-(NSNumber*(^)(float))divide;

@end
  
  
// NSNumber+CalculateChain2.m
#import "NSNumber+CalculateChain2.h"

@implementation NSNumber (CalculateChain2)


-(NSNumber*(^)(float))add{
    return ^NSNumber *(float value){
        return [NSNumber numberWithFloat:([self floatValue] + value)];
    };
}


-(NSNumber*(^)(float))minus{
    return ^NSNumber *(float value){
        return [NSNumber numberWithFloat:([self floatValue] - value)];
    };
}


-(NSNumber*(^)(float))multiply{
    return ^NSNumber *(float value){
        return [NSNumber numberWithFloat:([self floatValue] * value)];
    };
}


-(NSNumber*(^)(float))divide{
    return ^NSNumber *(float value){
        return [NSNumber numberWithFloat:([self floatValue] / value)];
    };
}


@end

Reference

Demo Project on Github: https://github.com/arkilis/Method-Chaining-in-Objective-C/