发布于2026-07-21 阅读(0)
扫一扫,手机访问
提到链式编程和函数式编程,最典型的代表是Masonry,它比较完美地实现了这两种编程风格。例如:
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view).offset(100);
make.centerX.equalTo(self.view.mas_centerX).offset(100);
make.height.mas_equalTo(100);
make.width.mas_equalTo(100);
}];复制代码
所谓的链式编程,说白了就是在返回值的基础上继续调用方法。那么问题来了:什么样的返回值才能继续调用方法?答案很简单——返回对象。只要返回一个对象,然后继续调用该对象的对象方法,就能实现链式编程。
举个简单的例子:先定义一个Person类,添加两个对象方法:
-(void)play;
-(void)run;复制代码
-(void)play{
NSLog(@"play");
}
-(void)run{
NSLog(@"run");
}复制代码
在ViewController中调用:
Person * xiaoming = [Person new];
[xiaoming play];复制代码
现在我们想要实现的是 [[xiaoming play]run],所以 play 方法的返回值就不能为空,应该返回 Person 对象:
-(Person *)play;
-(Person *)play{
return self;
}复制代码
这样一来,[[xiaoming play]run] 就顺利实现了。
不过,这种链式编程和 Masonry 相比还是差了点意思。我们知道在 OC 中,方法调用是通过发送消息的方式实现的,那么要实现 person.eat 这种点语法该怎么处理?
-(void(^)(void))play2;复制代码
-(void (^)(void))play2{
return ^(){
NSLog(@"play2");
};
}复制代码
这样就能实现 [xiaoming play].play2(); 了。
如果后续还想继续添加点方法,思路相同,只需要让返回值始终是 Person 对象即可:
-(Person *(^)(NSString * str))play2;
-(void(^)(NSString * str))play3;复制代码
- (Person *(^)(NSString *str))play2{
return ^(NSString *str){
NSLog(@"%@",str);
return self;
};
}
-(void (^)(NSString * str))play3{
return ^(NSString * str){
NSLog(@"%@",str);
};
}复制代码
这样就能实现 xiaoming.play2(@"33").play3(@"333"); 这种连续调用。
上面的方法本质是通过 block 返回当前对象,从而实现点语法连续调用。
函数式编程,就是通过类似函数调用的方式来实现想要的功能,即 method(); 这样的形式。在 OC 中,能用 method() 这种形式调用的,只有 block。我们在调用 block 时不就是这么写的吗?所以,只要一个方法的返回值是 block,就可以使用函数式调用。
定义构造方法:
+(instancetype)initWithP:(void(^)(Person * p))Block;复制代码
+(instancetype)initWithP:(void (^)(Person *))Block{
Person * p = [Person new];
return p;
}复制代码
可以调用返回值为 p 的函数式构造方法,然后在内部对 p 对象进行操作:
[Person initWithP:^(Person *p) {}];复制代码
这样就可以调用链式方法了:
[Person initWithP:^(Person *p) {
p.play2(@"222").play3(@"3333");
}];复制代码
上面都是通过定义方法来实现点语法调用,但我们的编程习惯通常是用点语法来调取类的成员属性。OC 的点语法中,.XX 是 getter,.XX=XXX 是 setter。显然链式编程是一串连续的调用,所以应该想到把 block 声明为属性,并在这些 block 属性的 getter 方法中做些事情。
在 Person 类中添加成员属性:
@property(nonatomic,readonly,copy)Person *(^eat)(NSString * str);复制代码
重写成员属性的 getter 方法:
-(Person *(^)(NSString *))eat{
return ^(NSString* eat){
NSLog(@"%@",eat);
return self;
};
}复制代码
这样就能用点语法调用 eat 方法了:
[Person initWithP:^(Person *p) {
p.play2(@"222").eat(@"333").play3(@"444");
}];复制代码
定义属性相比定义方法,一个突出的优点就是输入时会有代码提示,所以更常用。
现在我们要在 VC 上添加四个大小相同、圆角为 2 的红色 view,实现代码如下:
@interface MYView : UIView
+(instancetype)initWith:(void(^)(MYView *view))BLOCK;
@property(nonatomic,readonly,copy)MYView *(^viewFrame)(CGRectframe);
@property(nonatomic,readonly,copy)MYView * (^layerCornerRadious)(CGFloat radious);
@property(nonatomic,copy,readonly)MYView*(^ColorString)(NSString * colorStr);
@end复制代码
+(instancetype)initWith:(void (^)(MYView *))BLOCK{
MYView * view = [[MYView alloc]init];
if (BLOCK) {
BLOCK(view);
}
return view;
}
-(MYView *(^)(CGRect))viewFrame{
return^MYView*(CGRect rect){
self.frame = rect;
return self;
};
}
-(MYView *(^)(CGFloat))layerCornerRadious{
return ^MYView*(CGFloat radious){
self.layer.cornerRadius = radious;
self.layer.masksToBounds = YES;
return self;
};
}
-(MYView *(^)(NSString *))ColorString{
return ^MYView* (NSString * colorStr){
self.backgroundColor = [UIColor redColor];
return self;
};
}复制代码
在 VC 中只需调用:
[self.view addSubview:[MYView initWith:^(MYView *View) {
View.viewFrame(CGRectMake(100, 200, 20, 20)).layerCornerRadious(2).ColorString(@"颜色自己设置");
}]];复制代码 上一篇:scratch编程
下一篇:什么是编程?为什么要编程?
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8