Objective-C 鏈?zhǔn)骄幊?/h2>
這是每一個人想要的辦公環(huán)境吧

最近看到了鏈?zhǔn)骄幊毯秃瘮?shù)式編程這兩個概念,網(wǎng)上查了一些資料,但是發(fā)現(xiàn)資料都千篇一律,我心中存在的這幾個疑惑根本沒有幫我解開。
1,為什么可以使用.語法來調(diào)用方法,而不是使用OC里面的[ ]。
2,為什么方法里面明明沒有參數(shù),當(dāng)方法的返回值是一個block時(shí),使用.語法調(diào)用方法可以傳參數(shù)。
不知道有沒有和我遇到一樣的問題的同學(xué),周末的時(shí)間用了一個下午一點(diǎn)一點(diǎn)琢磨。下面我來一一解釋這些問題。
首先,先簡紹下block

block的作用,主要用于回調(diào)傳值,解耦合
1.當(dāng)方法的參數(shù)是block類型,block的參數(shù)用于從內(nèi)向外傳值
2.block的返回值用于從外向內(nèi)返回結(jié)果

這兩句話是能實(shí)現(xiàn)鏈?zhǔn)骄幊痰年P(guān)鍵,好好理解下。

對于block,我們可以這樣理解
舉個例子:大家想必都看過警匪片,在片子里面,壞蛋都喜歡安裝一些遙控的炸彈來威脅警察,如果警察不聽話,壞蛋就會引爆炸彈。這里的炸彈就可以理解為block,而遙控器就可以理解為調(diào)用block。block就是我們提前存儲的一段代碼塊,當(dāng)我們需要使用的時(shí)候才去調(diào)用它。下面來看一段網(wǎng)絡(luò)請求數(shù)據(jù)的代碼來理解下這個遙控炸彈。

@interface ReuuestData : NSObject

//定義無參數(shù)無返回值的block
- (void)requestDataSucc:(void(^)())succBlock fail:(void(^)())failBlock;
@end
@implementation ReuuestData
- (void)requestDataSucc:(void (^)())succBlock fail:(void (^)())failBlock {
//這一塊就相當(dāng)于炸彈的遙控器, 在成功或者失敗里引爆炸彈
    if (/* DISABLES CODE */ (YES)) {
        succBlock(); //成功的block
    }else {
        failBlock(); //失敗的block
    }
}
@end

下面我們在ViewController里使用下

ReuuestData *obj = [ReuuestData alloc] init];
//這一塊就相當(dāng)于埋了一個炸彈, 我們不管他什么時(shí)候會爆炸,決定他爆炸的時(shí)刻是安裝了這個炸彈接收信號的遙控器
[obj requestDataSucc:^{
        //成功的回調(diào)
    } fail:^{
        //失敗的回調(diào)
    }];

因?yàn)槲覀冊谶M(jìn)行網(wǎng)絡(luò)請求時(shí)不知道什么時(shí)候請求會成功, 我們首先讓obj 調(diào)用請求網(wǎng)絡(luò)的方法, 此時(shí),開始網(wǎng)絡(luò)請求, 當(dāng)請求結(jié)束后,會走對應(yīng)的成功或者失敗的方法。


接下來理解了上面的網(wǎng)絡(luò)請求的例子,咱們就以一個例子來講解鏈?zhǔn)骄幊?,這個例子在其他文章中也都有介紹,為了保證文章的完整性,我就再啰嗦一遍這個例子。
1、首先創(chuàng)建一個Person類,并為其增加兩個方法

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

2、實(shí)現(xiàn)方法

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

3、實(shí)例化對象,并調(diào)用方法

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

以上三部很簡單,相比大家都能看的懂。而我們最終的目標(biāo)是

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

首先我們要實(shí)現(xiàn)

 [[person name] sex];

實(shí)現(xiàn)這個目標(biāo)很簡單,只需要調(diào)用[person name]的時(shí)候返回一個Person對象就可以了,下面我們來修改代碼

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

這樣就可以實(shí)現(xiàn)了,

[[person name2] sex2];

這離我們的最終目標(biāo)還有一段距離。
先拆分下目標(biāo),先實(shí)現(xiàn)

    [[person name](@"Jason") sex](@"男"); //這個是不是和我們最終的目標(biāo)很像,只需把中括號換成(.)就可以了

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

我們都知道OC里面調(diào)用方法使用的是[obj func],向一個方法發(fā)送一條消息。而沒有obj.func(param)的形式,要想實(shí)現(xiàn)這個,我們自然而然的會想到OC里面的block,只有block才是以()的方式調(diào)用的。
1、我們可以返回一個block,然后使用()去掉用。
2、那么我們要如何實(shí)現(xiàn)連續(xù)調(diào)用呢?我們再分析,要調(diào)用一個類的實(shí)例方法,必須由這個類的實(shí)例對象才能調(diào)用,如[[person name] sex]; 我們之所以可以連續(xù)使用[ ], 是因?yàn)槲覀兎祷亓艘粋€該實(shí)例對象。如果在返回的block里面返回一個實(shí)例對象不就可以連續(xù)調(diào)用了嗎,而block正好也能返回一個對象。下面我們再改寫代碼。

//返回一個block,而block的返回值是一個Person對象
- (Person * (^)())name3;
- (Person * (^)())sex3;
- (Person * (^)())name3 {
//可以直接返回一個block
    return ^Person *(){
        return self;
    };
}
- (Person * (^)())sex3 {
//也可以定義一個block,接收返回的block,再把block返回
//等號右邊的Person *()可以省略不寫,Person *省略不寫的原因是返回值本身可以不寫,()可以省略不寫的原因是block無參數(shù)時(shí)可以省略()
    Person *(^block)() = ^Person *(){
        return self;
    };
    return block;
}

此時(shí)我們調(diào)用方法

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

看到如此的寫法是不是很奇怪, OC里面調(diào)用方法沒有這樣寫的呀,不要著急,我們一步一步分解。

[person name3]

這一步大家都很熟悉吧,我們在前面講過,name3方法返回的是一個block,我們打印下這個返回值,看看到底是個什么鬼?

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

打印結(jié)果告訴我們,返回值是一個block

//這種寫法就相當(dāng)于我們?nèi)フ{(diào)用了一個block,前面說過,只有block才會有()的這種語
//還記得前面講的定時(shí)炸彈嗎,當(dāng)執(zhí)行完[person name3]這句代碼的時(shí)候,我們就找到了那個炸彈,再執(zhí)行()的時(shí)候,我們就引爆了炸彈。
[person name3]()

前面說過,block也是有返回值的,我們同樣打印下block的返回值

NSLog(@"%@", [person name3]());
<Person: 0x7fd9e9daf980> //返回值是一個對象,很關(guān)鍵

接下來我們換一種寫法來理解這句代碼,把這句代碼分成兩步。

//1.聲明一個返回值是Person類型, 無參數(shù)的block,用于接收返回值
    Person * (^returnBlock)() = [person name3];
    NSLog(@"%@", [person name3]); //<__NSMallocBlock__: 0x7f93bfc105a0>
    NSLog(@"%@", returnBlock);    //<__NSMallocBlock__: 0x7f93bfcb7a00>
//2.調(diào)用block
    returnBlock(); //注意此處返回的是一個Person對象, 這是我們實(shí)現(xiàn)鏈?zhǔn)骄幊痰年P(guān)鍵
    NSLog(@"%@", returnBlock()); //<Person: 0x7fd9e9daf980>

上面的寫法是不是容易理解一點(diǎn)呢,首先聲明一個返回值是Person類型, 無參數(shù)的block,用于接收[person name3]的返回值, 此時(shí)我們找到了我們先前已經(jīng)存好的block(炸彈),然后再去調(diào)用block(引爆炸彈)
下面我們再來看之前的代碼

    [[person name3]() sex3]();
  //這一步操作分解之后就是這四步, 此處也能看出,鏈?zhǔn)骄幊棠芴岣唛_發(fā)效率和提高代碼的可讀性
    Person * (^returnNameBlock)() = [person name3];
    Person *personName = returnNameBlock();
    Person * (^returnSexBlock)() = [personName sex3];
    Person *personSex = returnSexBlock();

此時(shí)離我們最終實(shí)現(xiàn)的效果的前一步還差一點(diǎn),就是沒有參數(shù),我們再改寫代碼,加上參數(shù),實(shí)現(xiàn)下面的效果

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

改寫

// 函數(shù)的返回值是一個Block,Block的返回值是當(dāng)前對象,Block有一個參數(shù)
- (Person * (^)(NSString *name))name4; //設(shè)置參數(shù)
- (Person * (^)(NSString *sex))sex4;
- (Person * (^)(NSString *name))name4 {
// 方法的返回是一個”有參有返回值的Block“
    return ^Person *(NSString *name){
        NSLog(@"%@", name);
// block的返回值是當(dāng)前對象
        return self;
    };
}
- (Person * (^)(NSString *sex))sex4 {
    return ^Person *(NSString *sex) {
        NSLog(@"%@", sex);
        return self;
    };
}

//調(diào)用

//(@"Jason")這個參數(shù)是block的參數(shù),并且是block作為返回值的參數(shù),在文章的開頭已經(jīng)說過,block的返回值參數(shù)用于從外向內(nèi)返回結(jié)果,這就是為什么我們在外面?zhèn)魅雲(yún)?shù)(@"Jason"),而在函數(shù)內(nèi)部會打印我們傳入的參數(shù),這點(diǎn)不要搞錯。-->>解釋文章開頭第二個問題
[[person name4](@"Jason") sex4](@"男");

OK,經(jīng)歷九九八十一難,我們終于到達(dá)了天竺,離求取真經(jīng)只差一步了
我們要的結(jié)果是

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

而我們現(xiàn)在的結(jié)果和這個目標(biāo)只差一步了,是不是感覺有點(diǎn)小激動呢。
還是文章開頭的第一個問題-->> 為什么可以使用.語法來調(diào)用方法,而不是使用OC里面的[ ]。
首先我們要知道OC里面的屬性聲明默認(rèn)是私有的,外部是不可以直接訪問的,而setter個getter方法是可以間接訪問屬性的。其實(shí)在使用self.propert語法時(shí),不是直接訪問屬性,而是隱士的調(diào)用了setter或者getter方法來訪問屬性的,在編譯與運(yùn)行期間,并不關(guān)心你是否在真正的在獲取一個屬性。要實(shí)現(xiàn)使用.點(diǎn)語法調(diào)用方法,你的方法,必須有一個返回值,并且無參數(shù)。這樣才符合getter方法的書寫規(guī)范,而我們最終使用的方法整好符合這種規(guī)范。所以,你就可以直接使用 person.name(@"Jason").sex(@"男");來調(diào)用方法了。

最終我們實(shí)現(xiàn)了

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

你可以盡情的 . 下去了


關(guān)于文章的第一個問題 -->> 為什么可以使用.語法來調(diào)用方法,而不是使用OC里面的[ ], 不知道自己的理解是否準(zhǔn)確,如果有錯誤,還請簡友門幫忙糾正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容