轉(zhuǎn)自
Objective-C 鏈?zhǔn)骄幊?br>
最近看到了鏈?zhǔn)骄幊毯秃瘮?shù)式編程這兩個概念代兵,網(wǎng)上查了一些資料,但是發(fā)現(xiàn)資料都千篇一律,我心中存在的這幾個疑惑根本沒有幫我解開颇玷。
1,為什么可以使用.語法來調(diào)用方法宠能,而不是使用OC里面的[ ]亚隙。
2,為什么方法里面明明沒有參數(shù)违崇,當(dāng)方法的返回值是一個block時阿弃,使用.語法調(diào)用方法可以傳參數(shù)。
不知道有沒有和我遇到一樣的問題的同學(xué)羞延,周末的時間用了一個下午一點一點琢磨渣淳。下面我來一一解釋這些問題。
首先伴箩,先簡紹下block
block的作用,主要用于回調(diào)傳值,解耦合
1.當(dāng)方法的參數(shù)是block類型,block的參數(shù)用于從內(nèi)向外傳值
2.block的返回值用于從外向內(nèi)返回結(jié)果
這兩句話是能實現(xiàn)鏈?zhǔn)骄幊痰年P(guān)鍵入愧,好好理解下。
對于block,我們可以這樣理解
舉個例子:大家想必都看過警匪片瞎领,在片子里面瓮增,壞蛋都喜歡安裝一些遙控的炸彈來威脅警察,如果警察不聽話旁赊,壞蛋就會引爆炸彈。這里的炸彈就可以理解為block椅野,而遙控器就可以理解為調(diào)用block终畅。block就是我們提前存儲的一段代碼塊,當(dāng)我們需要使用的時候才去調(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)于埋了一個炸彈炼蛤, 我們不管他什么時候會爆炸妖爷,決定他爆炸的時刻是安裝了這個炸彈接收信號的遙控器
[obj requestDataSucc:^{
//成功的回調(diào)
} fail:^{
//失敗的回調(diào)
}];
因為我們在進(jìn)行網(wǎng)絡(luò)請求時不知道什么時候請求會成功, 我們首先讓obj 調(diào)用請求網(wǎng)絡(luò)的方法理朋, 此時赠涮,開始網(wǎng)絡(luò)請求子寓, 當(dāng)請求結(jié)束后,會走對應(yīng)的成功或者失敗的方法笋除。
接下來理解了上面的網(wǎng)絡(luò)請求的例子斜友,咱們就以一個例子來講解鏈?zhǔn)骄幊蹋@個例子在其他文章中也都有介紹垃它,為了保證文章的完整性鲜屏,我就再啰嗦一遍這個例子。
1国拇、首先創(chuàng)建一個Person類洛史,并為其增加兩個方法
(void)name1;
(void)sex1;
2、實現(xiàn)方法(void) name1 {
NSLog(@"name");
}(void) sex1 {
NSLog(@"sex")
}
3酱吝、實例化對象也殖,并調(diào)用方法
Person*person = [[Personalloc]init];
[person name1];
[person sex1];
以上三部很簡單,相比大家都能看的懂务热。而我們最終的目標(biāo)是
person.name(@"Jason").sex(@"男");
首先我們要實現(xiàn)
[[person name] sex];
實現(xiàn)這個目標(biāo)很簡單忆嗜,只需要調(diào)用[person name]的時候返回一個Person對象就可以了,下面我們來修改代碼
- (Person *)name2;
- (Person *)sex2;
- (Person *)name2 {
NSLog(@"name");
return self;
} - (Person *)sex2 {
NSLog(@"sex");
return self;
}
這樣就可以實現(xiàn)了崎岂,
[[person name2] sex2];
這離我們的最終目標(biāo)還有一段距離捆毫。
先拆分下目標(biāo),先實現(xiàn)
[[person name](@"Jason") sex](@"男"); //這個是不是和我們最終的目標(biāo)很像冲甘,只需把中括號換成(.)就可以了
person.name(@"Jason").sex(@"男");
我們都知道OC里面調(diào)用方法使用的是[obj func]绩卤,向一個方法發(fā)送一條消息。而沒有obj.func(param)的形式江醇,要想實現(xiàn)這個濒憋,我們自然而然的會想到OC里面的block,只有block才是以()的方式調(diào)用的陶夜。
1跋炕、我們可以返回一個block,然后使用()去掉用律适。
2、那么我們要如何實現(xiàn)連續(xù)調(diào)用呢遏插?我們再分析捂贿,要調(diào)用一個類的實例方法,必須由這個類的實例對象才能調(diào)用胳嘲,如[[person name] sex]; 我們之所以可以連續(xù)使用[ ]厂僧, 是因為我們返回了一個該實例對象。如果在返回的block里面返回一個實例對象不就可以連續(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ù)時可以省略()
Person *(^block)() = ^Person *(){
return self;
};
return block;
}
此時我們調(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才會有()的這種語
//還記得前面講的定時炸彈嗎前域,當(dāng)執(zhí)行完[person name3]這句代碼的時候,我們就找到了那個炸彈韵吨,再執(zhí)行()的時候匿垄,我們就引爆了炸彈。
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對象铝条, 這是我們實現(xiàn)鏈?zhǔn)骄幊痰年P(guān)鍵
NSLog(@"%@", returnBlock()); //<Person: 0x7fd9e9daf980>
上面的寫法是不是容易理解一點呢,首先聲明一個返回值是Person類型席噩, 無參數(shù)的block班缰,用于接收[person name3]的返回值, 此時我們找到了我們先前已經(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();
此時離我們最終實現(xiàn)的效果的前一步還差一點,就是沒有參數(shù)莹妒,我們再改寫代碼名船,加上參數(shù),實現(xiàn)下面的效果
person name 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ù)谋梭,這點不要搞錯。-->>解釋文章開頭第二個問題
person name4 sex4;
OK倦青,經(jīng)歷九九八十一難瓮床,我們終于到達(dá)了天竺,離求取真經(jīng)只差一步了
我們要的結(jié)果是
person.name(@"Jason").sex(@"男");
而我們現(xiàn)在的結(jié)果和這個目標(biāo)只差一步了产镐,是不是感覺有點小激動呢隘庄。
還是文章開頭的第一個問題-->> 為什么可以使用.語法來調(diào)用方法,而不是使用OC里面的[ ]癣亚。
首先我們要知道OC里面的屬性聲明默認(rèn)是私有的丑掺,外部是不可以直接訪問的,而setter個getter方法是可以間接訪問屬性的述雾。其實在使用self.propert語法時街州,不是直接訪問屬性,而是隱士的調(diào)用了setter或者getter方法來訪問屬性的玻孟,在編譯與運行期間唆缴,并不關(guān)心你是否在真正的在獲取一個屬性。要實現(xiàn)使用.點語法調(diào)用方法黍翎,你的方法面徽,必須有一個返回值,并且無參數(shù)匣掸。這樣才符合getter方法的書寫規(guī)范趟紊,而我們最終使用的方法整好符合這種規(guī)范。所以碰酝,你就可以直接使用 person.name(@"Jason").sex(@"男");來調(diào)用方法了霎匈。
最終我們實現(xiàn)了
person.name(@"Jason").sex(@"男");
你可以盡情的 . 下去了