面向对象的语言有三个特点,封装 继承 多态,这会说的链式编程是基于封装这一特点的延伸
Masonry是iOS开发中经常使用的框架,它就是一个链式编程的经典例子,把控件的约束条件写在一个block里面,一次性完成对某个控件的约束,而且使用点语法写起来干净潇洒,省去了OC中最反人类的[],当然,最终使用与否还是看个人习惯以及团队协作的便利性;
链式编程的思路之神奇的点语法
用过Masonry的朋友们会发现虽然里面在一次又一次的调用方法,可是却没有用到[],而是频繁的用点来操作.这其实是一个开发者容易遗漏的神奇地方.
eg.
NSMutableString *mutableString = [NSMutableString string];
mutableString.copy;//1
[mutableString copy];//2
写法1会报"property access result unused - getters should not be used for side effects"这个么一个警告,这个不受影响,因为我们现在没有将执行结果赋给其他变量所有会有这个警告使用[]调用方法即使方法有返回值在我们不接收返回值的时候也不会出现警告.我们将写法1写成这样就可以将警告消除.
(void)mutableString.copy;
就实际的使用来看,二者并没有什么区别,那我们当然会想,这是不是Foundation框架在内部进行了什么处理才可以这样调用了,于是我们照葫芦画瓢.
- (void)hehe{
NSLog(@"123,hehe");
}
- (void)viewDidLoad {
[super viewDidLoad];
(void)self.hehe;
}
控制台结果是
[25253:1097886] 123,hehe
这么一来我们的链式编程点语法就的秘密就解开了.由于链式点语法的返回值我们每次都会循环使用(实际上返回值是一个返回值为self的block),所以我们也不会看到链式点语法中(void)的出现.
奇葩的返回值
大家一定都多多少看过Masonry框架的底层代码,可以看到每次点语法的调用返回的总是一个约束.
eg.
- (MASConstraint *)edges
- (MASConstraint * (^)(id))equalTo
调用的的时候是
make.edges.mas_equalTo(0);
所以单纯返回一个可以循环调用的类型就可以进行基本的链式编程了,可是如果要接参,没办法,我们只能把返回值类型写成==>带参数的返回值为可循环类型的block.
开工-来一个小demo
#import <UIKit/UIKit.h>
@class JJButton;
typedef JJButton *(^JJButtonStringBlock)(NSString *aName);//typedef一个返回值为JJButton* 参数为NSString* 的名字为JJButtonStringBlock的block,方便以后快速定义该类型block
typedef JJButton *(^JJButtonIntegerBlcok)(NSUInteger aNumber);
typedef JJButton *(^JJButtonColorBlock)(UIColor *aColor);
@interface JJButton : UIButton
- (JJButtonStringBlock)imageName;
- (JJButtonStringBlock)title;
- (JJButtonIntegerBlcok)titleFont;
- (JJButtonColorBlock)textColor;
+ (JJButton *)makeJJButton:(void (^)(JJButton *))block;//该方法为工厂方法,能够快速创建一个JJButton,在一个参数为block的方法中一次性设置好你需要的JJButton
@end
不多说了,下面是方法的实现
#import "JJButton.h"
@implementation JJButton
- (JJButtonStringBlock)imageName{
return ^JJButton *(NSString *aName){
[self setImage:[UIImage imageNamed:aName] forState:UIControlStateNormal];
NSLog(@"imageName");
return self;
};
}
- (JJButtonStringBlock)title{
return ^JJButton *(NSString *aName){
[self setTitle:aName forState:UIControlStateNormal];
NSLog(@"title");
return self;
};
}
- (JJButtonIntegerBlcok)titleFont{
return ^JJButton *(NSUInteger aNumber){
self.titleLabel.font = [UIFont systemFontOfSize:aNumber];
NSLog(@"titleFont");
return self;
};
}
- (JJButtonColorBlock)textColor{
return ^JJButton *(UIColor *aColor){
[self setTitleColor:aColor forState:UIControlStateNormal];
NSLog(@"textColor = %@",aColor);
return self;
};
}
+ (JJButton *)makeJJButton:(void (^)(JJButton *))block{
JJButton * button = [[JJButton alloc] init];
block(button);
return button;
}
@end
调用
JJButton *myButton = ({
JJButton *button = [[JJButton alloc] init];
button.title(@"heiheihei").imageName(@"3").titleFont(15).textColor([UIColor blackColor]);
button.frame = CGRectMake(100, 100, 100, 100);
[button addTarget:self action:@selector(didClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
button;
});
上诉方法是不适用工厂方法的调用,我使用了GCC语法,这种语法看上去比较规整.
下面是工厂方法
[JJButton makeJJButton:^(JJButton *button) {
button.title(@"xixixi").imageName(@"abc").titleFont(20).textColor([UIColor orangeColor]);
button.frame = CGRectMake(100, 250, 100, 100);
[self.view addSubview:button];
[button addTarget:self action:@selector(didClick:) forControlEvents:UIControlEventTouchUpInside];
}];
这种方法大家应该就分厂熟悉了,它与Masonry那种链式编程写法非常相似了,在工厂方法中我们在类方法内部进行了初始化,相当于进行了更加彻底的封装.
萝卜青菜各有所爱哈~
版权声明:本文版权归本文作者所有,始发于简书,如需转载请联系作者,违者必究.