這周給大家分享的iOS知識(shí)算是蠻有意思的朴皆,用寫Java方法調(diào)用的語(yǔ)法來寫Objective-C帕识。沒有什么高大上的技術(shù),有的只是Block的使用技巧遂铡。前些天在讀這篇RAC源碼解析的文章 的時(shí)候肮疗,聯(lián)想到了Masonry/BlocksKit兩個(gè)三方框架,它們?nèi)即罅渴褂玫搅薆lock扒接,其中就有類似Java語(yǔ)法來寫Objective-C的例子伪货。
首先我們來看看普通的Block是什么樣的:
int (^myBlock1) (int, int) = ^(int a, int b) {
return a + b;
};
int s = myBlock1(1, 2);
NSLog(@"s = %i", s);
上面定義了一個(gè)名字叫做myBlock1的block,它接受兩個(gè)int類型的參數(shù)钾怔,并且返回int超歌。
而Masonry這個(gè)框架中,它的Block是這樣的:
[view makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.view);
make.top.equalTo(self.view.top).offset(40);
make.bottom.equalTo(self.view.bottom).offset(-20);
make.width.equalTo(self.view.width).multipliedBy(0.8);
}];
我們看到其中的
make.width.equalTo(self.view.width).multipliedBy(0.8);
非常類似Java中的方法調(diào)用的寫法蒂教。
我們來研究下如何實(shí)現(xiàn)以上這種寫法。
首先我們定義一個(gè)Student對(duì)象脆荷,它由兩個(gè)方法play和study凝垛。
我們希望外部是這么調(diào)用它的:
Student *student = [[Student alloc] init];
student.study().play().study().play();
以前在寫Java解析XML的代碼時(shí),我經(jīng)常寫到node.setText("xxx").setAttribute("xxx")蜓谋。這種方法調(diào)用的關(guān)鍵在于方法調(diào)用完會(huì)返回一個(gè)調(diào)用者對(duì)象梦皮,受此啟發(fā),我們可以在發(fā)送消息時(shí)返回發(fā)送消息的sender桃焕。而在iOS中是使用方括號(hào)進(jìn)行消息發(fā)送剑肯,如果要加()則需要使用block。
因此我們有:
- (Student *(^)())study
{
return ^() {
NSLog(@"study");
return self;
};
}
其中观堂,Student *(^)()表示一種Block類型让网,該Block不接受任何參數(shù),返回類型為Student师痕。
demo中的
student.study 等價(jià)于 [student study]
student.study() 等價(jià)于 student study
相當(dāng)于拿到返回的Block并直接執(zhí)行溃睹,繼續(xù)返回self,即student對(duì)象胰坟,因此可以繼續(xù)調(diào)用student對(duì)象方法
那有參數(shù)的情況是什么樣的呢因篇?我們想要這樣調(diào)用:
student.study().play(@"Dota").study().play(@"Pokemon”);
輸出:
2015-09-13 22:30:07.858 TestLinkedBlock[1478:27604] study
2015-09-13 22:30:07.858 TestLinkedBlock[1478:27604] play Dota
2015-09-13 22:30:07.858 TestLinkedBlock[1478:27604] study
2015-09-13 22:30:07.859 TestLinkedBlock[1478:27604] play Pokemon
既然點(diǎn)語(yǔ)法只支持沒有參數(shù)的方法,那我們可以試試把參數(shù)放在Block中:
- (Student *(^)(NSString *gameName))play
{
return ^(NSString *gameName) {
NSLog(@"play %@", gameName);
return self;
};
}
這樣的話,play方法就返回一個(gè)Block竞滓,它接受一個(gè)NSString *類型的參數(shù)咐吼,與調(diào)用方式非常吻合。
我們?cè)賮砜纯碝asonry中的用法:
make.width.equalTo(self.view.width).multipliedBy(0.8);
它的源碼是這樣的:
- (MASConstraint * (^)(CGFloat))multipliedBy {
return ^id(CGFloat multiplier) {
for (MASConstraint *constraint in self.childConstraints) {
constraint.multipliedBy(multiplier);
}
return self;
};
}
返回一個(gè)Block商佑,該Block接受一個(gè)CGFloat锯茄,返回自身類型,從而實(shí)現(xiàn)鏈?zhǔn)降腂lock語(yǔ)法莉御。
最后我們嘗試在UIKit上做一些Extension:
我們想要這樣調(diào)用view來設(shè)置它的一些基本屬性:
UIView *view = [[UIView alloc] init];
[self.view addSubview:view];
view.ff_setFrame(CGRectMake(20, 20, 20, 20)).ff_setBackgroundColor([UIColor redColor]);
方法也很簡(jiǎn)單:
(UIView *(^)(CGRect))ff_setFrame
{
return ^(CGRect rect) {
self.frame = rect;
return self;
};
}(UIView *(^)(UIColor *))ff_setBackgroundColor
{
return ^(UIColor *color) {
self.backgroundColor = color;
return self;
};
}