Method Chaining in Objective-C and make your own Chaining Methods to create a calculator



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);
@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);

Be aware about the method:

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

Which is a getter for property minus, it takes a

Some Improvements:

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

If you have any thoughts, please leave a comment.

Reference

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

About: arkilis


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.