Objective-C 链式编程

这是每一个人想要的办公环境吧

最近看到了链式编程和函数式编程这两个概念,网上查了一些资料,但是发现资料都千篇一律,我心中存在的这几个疑惑根本没有帮我解开。
1,为什么可以使用.语法来调用方法,而不是使用OC里面的[ ]。
2,为什么方法里面明明没有参数,当方法的返回值是一个block时,使用.语法调用方法可以传参数。
不知道有没有和我遇到一样的问题的同学,周末的时间用了一个下午一点一点琢磨。下面我来一一解释这些问题。
首先,先简绍下block

block的作用,主要用于回调传值,解耦合
1.当方法的参数是block类型,block的参数用于从内向外传值
2.block的返回值用于从外向内返回结果

这两句话是能实现链式编程的关键,好好理解下。

对于block,我们可以这样理解
举个例子:大家想必都看过警匪片,在片子里面,坏蛋都喜欢安装一些遥控的炸弹来威胁警察,如果警察不听话,坏蛋就会引爆炸弹。这里的炸弹就可以理解为block,而遥控器就可以理解为调用block。block就是我们提前存储的一段代码块,当我们需要使用的时候才去调用它。下面来看一段网络请求数据的代码来理解下这个遥控炸弹。

@interface ReuuestData : NSObject

//定义无参数无返回值的block
- (void)requestDataSucc:(void(^)())succBlock fail:(void(^)())failBlock;
@end
@implementation ReuuestData
- (void)requestDataSucc:(void (^)())succBlock fail:(void (^)())failBlock {
//这一块就相当于炸弹的遥控器, 在成功或者失败里引爆炸弹
    if (/* DISABLES CODE */ (YES)) {
        succBlock(); //成功的block
    }else {
        failBlock(); //失败的block
    }
}
@end

下面我们在ViewController里使用下

ReuuestData *obj = [ReuuestData alloc] init];
//这一块就相当于埋了一个炸弹, 我们不管他什么时候会爆炸,决定他爆炸的时刻是安装了这个炸弹接收信号的遥控器
[obj requestDataSucc:^{
        //成功的回调
    } fail:^{
        //失败的回调
    }];

因为我们在进行网络请求时不知道什么时候请求会成功, 我们首先让obj 调用请求网络的方法, 此时,开始网络请求, 当请求结束后,会走对应的成功或者失败的方法。


接下来理解了上面的网络请求的例子,咱们就以一个例子来讲解链式编程,这个例子在其他文章中也都有介绍,为了保证文章的完整性,我就再啰嗦一遍这个例子。
1、首先创建一个Person类,并为其增加两个方法

  - (void)name1;
  - (void)sex1;

2、实现方法

 - (void) name1 {
   NSLog(@"name");
  }
  - (void) sex1 {
   NSLog(@"sex")
  }

3、实例化对象,并调用方法

 Person*person = [[Personalloc]init];
 [person name1];
 [person sex1];

以上三部很简单,相比大家都能看的懂。而我们最终的目标是

person.name(@"Jason").sex(@"男");

首先我们要实现

 [[person name] sex];

实现这个目标很简单,只需要调用[person name]的时候返回一个Person对象就可以了,下面我们来修改代码

- (Person *)name2;
  - (Person *)sex2;
- (Person *)name2 {
    NSLog(@"name");
    return self;
}
- (Person *)sex2 {
    NSLog(@"sex");
    return self;
}

这样就可以实现了,

[[person name2] sex2];

这离我们的最终目标还有一段距离。
先拆分下目标,先实现

    [[person name](@"Jason") sex](@"男"); //这个是不是和我们最终的目标很像,只需把中括号换成(.)就可以了

    person.name(@"Jason").sex(@"男");

我们都知道OC里面调用方法使用的是[obj func],向一个方法发送一条消息。而没有obj.func(param)的形式,要想实现这个,我们自然而然的会想到OC里面的block,只有block才是以()的方式调用的。
1、我们可以返回一个block,然后使用()去掉用。
2、那么我们要如何实现连续调用呢?我们再分析,要调用一个类的实例方法,必须由这个类的实例对象才能调用,如[[person name] sex]; 我们之所以可以连续使用[ ], 是因为我们返回了一个该实例对象。如果在返回的block里面返回一个实例对象不就可以连续调用了吗,而block正好也能返回一个对象。下面我们再改写代码。

//返回一个block,而block的返回值是一个Person对象
- (Person * (^)())name3;
- (Person * (^)())sex3;
- (Person * (^)())name3 {
//可以直接返回一个block
    return ^Person *(){
        return self;
    };
}
- (Person * (^)())sex3 {
//也可以定义一个block,接收返回的block,再把block返回
//等号右边的Person *()可以省略不写,Person *省略不写的原因是返回值本身可以不写,()可以省略不写的原因是block无参数时可以省略()
    Person *(^block)() = ^Person *(){
        return self;
    };
    return block;
}

此时我们调用方法

[[person name3]() sex3]();

看到如此的写法是不是很奇怪, OC里面调用方法没有这样写的呀,不要着急,我们一步一步分解。

[person name3]

这一步大家都很熟悉吧,我们在前面讲过,name3方法返回的是一个block,我们打印下这个返回值,看看到底是个什么鬼?

NSLog(@"%@", [person name3]);
//<__NSMallocBlock__: 0x7fa7714193c0>

打印结果告诉我们,返回值是一个block

//这种写法就相当于我们去调用了一个block,前面说过,只有block才会有()的这种语
//还记得前面讲的定时炸弹吗,当执行完[person name3]这句代码的时候,我们就找到了那个炸弹,再执行()的时候,我们就引爆了炸弹。
[person name3]()

前面说过,block也是有返回值的,我们同样打印下block的返回值

NSLog(@"%@", [person name3]());
<Person: 0x7fd9e9daf980> //返回值是一个对象,很关键

接下来我们换一种写法来理解这句代码,把这句代码分成两步。

//1.声明一个返回值是Person类型, 无参数的block,用于接收返回值
    Person * (^returnBlock)() = [person name3];
    NSLog(@"%@", [person name3]); //<__NSMallocBlock__: 0x7f93bfc105a0>
    NSLog(@"%@", returnBlock);    //<__NSMallocBlock__: 0x7f93bfcb7a00>
//2.调用block
    returnBlock(); //注意此处返回的是一个Person对象, 这是我们实现链式编程的关键
    NSLog(@"%@", returnBlock()); //<Person: 0x7fd9e9daf980>

上面的写法是不是容易理解一点呢,首先声明一个返回值是Person类型, 无参数的block,用于接收[person name3]的返回值, 此时我们找到了我们先前已经存好的block(炸弹),然后再去调用block(引爆炸弹)
下面我们再来看之前的代码

    [[person name3]() sex3]();
  //这一步操作分解之后就是这四步, 此处也能看出,链式编程能提高开发效率和提高代码的可读性
    Person * (^returnNameBlock)() = [person name3];
    Person *personName = returnNameBlock();
    Person * (^returnSexBlock)() = [personName sex3];
    Person *personSex = returnSexBlock();

此时离我们最终实现的效果的前一步还差一点,就是没有参数,我们再改写代码,加上参数,实现下面的效果

[[person name](@"Jason") sex](@"男");

改写

// 函数的返回值是一个Block,Block的返回值是当前对象,Block有一个参数
- (Person * (^)(NSString *name))name4; //设置参数
- (Person * (^)(NSString *sex))sex4;
- (Person * (^)(NSString *name))name4 {
// 方法的返回是一个”有参有返回值的Block“
    return ^Person *(NSString *name){
        NSLog(@"%@", name);
// block的返回值是当前对象
        return self;
    };
}
- (Person * (^)(NSString *sex))sex4 {
    return ^Person *(NSString *sex) {
        NSLog(@"%@", sex);
        return self;
    };
}

//调用

//(@"Jason")这个参数是block的参数,并且是block作为返回值的参数,在文章的开头已经说过,block的返回值参数用于从外向内返回结果,这就是为什么我们在外面传入参数(@"Jason"),而在函数内部会打印我们传入的参数,这点不要搞错。-->>解释文章开头第二个问题
[[person name4](@"Jason") sex4](@"男");

OK,经历九九八十一难,我们终于到达了天竺,离求取真经只差一步了
我们要的结果是

 person.name(@"Jason").sex(@"男");

而我们现在的结果和这个目标只差一步了,是不是感觉有点小激动呢。
还是文章开头的第一个问题-->> 为什么可以使用.语法来调用方法,而不是使用OC里面的[ ]。
首先我们要知道OC里面的属性声明默认是私有的,外部是不可以直接访问的,而setter个getter方法是可以间接访问属性的。其实在使用self.propert语法时,不是直接访问属性,而是隐士的调用了setter或者getter方法来访问属性的,在编译与运行期间,并不关心你是否在真正的在获取一个属性。要实现使用.点语法调用方法,你的方法,必须有一个返回值,并且无参数。这样才符合getter方法的书写规范,而我们最终使用的方法整好符合这种规范。所以,你就可以直接使用 person.name(@"Jason").sex(@"男");来调用方法了。

最终我们实现了

 person.name(@"Jason").sex(@"男");

你可以尽情的 . 下去了


关于文章的第一个问题 -->> 为什么可以使用.语法来调用方法,而不是使用OC里面的[ ], 不知道自己的理解是否准确,如果有错误,还请简友门帮忙纠正。

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

推荐阅读更多精彩内容