黑魔法:iOS链式编程

链式编程

在使用SDAutoLayout 自动视图布局时就已经发现这种链式编程。通过"." 将属性链接在一起形成如同一条链的编程方法。

 self.totalMoneyCount.sd_layout
.leftEqualToView(self)
.rightEqualToView(self)
.topSpaceToView(self.totalMoney, AutoHeight(15))
.autoHeightRatio(0);

核心实现原理:只要返回是本身这个对象

下列是普通方法的实现,稍候会对两个方法进行改变,形成一个普通的链式。

//Person 类 两个类中均无返回
-(void)goShopping{
    //todo
}

-(void)runing{
    //todo
}

Person *person = [[Person alloc]init];
[person goShopping];
[person runing]; 

普通方法的链式编程

//Person 类 两个类中均返回了本身
-(Person *)goShopping{
    //todo
    return self;
}

-(Person *)runing{
    //todo
    return self;
}

Person *person = [[Person alloc]init];
[[[person goShopping]runing]goShopping];

基本链式,你已经很明白了,但这种方式不美观,如果带参数,你会发现更不美观了,并且如果方法体中参数过长,串起来很难看。

Block形式的链式编程

如果你不太懂Block,那么我建议你先查看iOS之Block

-(Person* (^)(void))goShopping{
Person* (^block)(void) = ^() {
//在调用goShopping()Block时,执行了打印并返回自身,block执行完成,下一个链时,如果想让返回的block再调用对象的方法,那么这个block就需要返回一个对象,即返回block。
        NSLog(@"goShopping");
        return self;
    };
    return block;
}

-(Person* (^)(void))runing{

   Person* (^block)(void) = ^() {
        NSLog(@"runing");
        return self;
    };
    return block;
}

Person *person = [[Person alloc]init];
person.goShopping().runing().goShopping().runing();

到这里,你能很直观看见,block形式的链式比起普通方法的链式形式更美观。
其实很多人都有疑惑,(Person* (^)(void)) runing(^)(void)Person * 这啥意思?其实你可能和我一样,拆开看了,Person* (^)(void) 是一个以Block定义的整体,我第一次看有点懵,后来才看明白。现在我用typedef定义一下。

#import <Foundation/Foundation.h>

@interface Person : NSObject

//注意,typedef block形式要在interface之上才能被自动联想,然后移到interface之下,不然会已找不到Person而报错
typedef Person *(^PersonBlock)(void); 

@property(nonatomic,copy)PersonBlock personBlock;

-(PersonBlock)goShopping;
-(PersonBlock)runing;

@end

#import "Person.h"
@implementation Person

-(PersonBlock)goShopping{
    return ^(void){          
         //todo
         return self;
    };
}

-(PersonBlock)runing{
    return ^(void){
            //todo
        return self;
    };
}
@end

block里处理业务,最后return self 是为了返回本身,继续支持链式。

链式进价

你已经掌握了链式的结构,上面的链式足够你使用了,但你在实际使用时,发现block没有提示带值。完全需要手动,能明显感觉有缺陷。这时候就需要新增几个Block做成属性来替代普通方法。

我将删除无关的代码,包括上面提到过的,实现一个加法运算。

#import <Foundation/Foundation.h>
@interface Person : NSObject
typedef Person* (^Add)(CGFloat value);
// 加法,关于readonly:在调用时,防止出现self.addValue = ^Person *(CGFloat value) {};
@property(nonatomic,copy,readonly)Add addValue;
//计数和
@property(nonatomic,assign)CGFloat sum;
//运算
-(void)runIt;
@end

#import "Person.h"
@interface Person()
@property(nonatomic,copy)Add addValue;
@end
@implementation Person
-(Add)addValue{
    if (!_addValue) {

        //避免循环引用
        __weak typeof(self) weakSelf = self;
        _addValue = ^(CGFloat value){
            weakSelf.sum += value;
            return weakSelf;
        };
    }
    return _addValue;
}
-(void)runIt{
    self.addValue(2).addValue(45).addValue(56).addValue(5);
    NSLog(@"-->%lf",self.sum);
}
@end

链式编程进行分类扩展

因为我用的是Person类进行的加法运算,所以看起来有出处,很奇怪

#import <Foundation/Foundation.h>
#import "Person.h"
@interface NSObject (calculator)
+(CGFloat)Calculate:(void(^)(Person* person)) cal;
@end
@implementation NSObject (calculator)
+(CGFloat)Calculate:(void(^)(Person* person)) cal{
    Person *person = [[Person alloc]init];
    cal(person);
    return person.sum;
}
@end

使用

 CGFloat value = [NSObject Calculate:^(Person *person) {
        person.addValue(12).addValue(56).addValue(1);
    }];

    NSLog(@"->>>>%lf",value);

什么情况下适合链式编程

可以看出,链式编程像是“组合”的一种,不在乎调用的先后顺序(这句话可能不太准确,如果使用链式进行sql语句拼接,还是需要顺序),对于需要额外增加的,只需要新增一个属性。
并且调用方法可以一直调用同一个方法,比如:person.goShopping().goShopping().goShopping无限制。

所以总结:适合动态,可接收不在乎调用先后顺序,次数等动态需求。

至此,你已经掌握了链式编程了。

下一篇:黑魔法:iOS函数式编程

函数式编程和链式编程,微妙的关系


参考文

1. 深入浅出-iOS函数式编程的实现 && 响应式编程概念
2. 几种编程思想在iOS中的实现:(一)链式编程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容

  • 1 Block机制 (Very Good) Block技巧与底层解析 http://www.jianshu.com...
    Kevin_Junbaozi阅读 4,046评论 3 48
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,651评论 18 139
  • 提到链式编程和函数式编程,最典型的代表是Masonry 比较完美的实现了函数式编程和链式编程。例如 ``` [vi...
    iOS谢先森阅读 606评论 0 1
  • 转自Objective-C 链式编程最近看到了链式编程和函数式编程这两个概念,网上查了一些资料,但是发现资料都千篇...
    飞雨2013阅读 833评论 1 1
  • 九月十八号七点十三分,哪一天清晨,和往常一样,一宿舍同事都在睡梦中,然而就在这时,不料,莫名的被自己刺耳手机铃声惊...
    罗子僧阅读 634评论 6 7