可能被忽略掉編程技巧 之 鏈?zhǔn)骄幊?/h1>
@author Jou Email Weibo or Github
可能被忽略掉編程技巧 之 鏈?zhǔn)骄幊?/h1>
預(yù)熱 - 鏈?zhǔn)骄幊?/h2>
哎呦,不錯(cuò)哦。有點(diǎn)時(shí)間, 隨便寫篇文章,聊聊iOS中的鏈?zhǔn)骄幊獭?br>
鏈?zhǔn)骄幊蹋?如果你不是iOS開發(fā)者,相信你應(yīng)該沒聽過鏈?zhǔn)骄幊獭Φ模?鏈?zhǔn)骄幊?,并不是一種編程范式。鏈?zhǔn)骄幊踢@種表述, 應(yīng)該是在Objective-C獨(dú)有,因?yàn)镺bjective-C是一門繁瑣而奇怪的語言。
在Swift之前,想成為iOS開發(fā)者,在入門前你就有了兩個(gè)門檻: 1. 你要有臺蘋果, 2. 你要肯于接受Objective-C的反人類,和繁瑣。
所以形式上,鏈?zhǔn)骄幊淌?點(diǎn)方法"的調(diào)用,來彌補(bǔ)Objc的繁瑣。
Objective-C
NSString objc = @"Hello world";
[objc lowercaseString]; // 給objc 發(fā)送lowercaseString的消息
而相比之下swift 就更為簡潔
let str = "Hello, playground"
str.lowercaseString;
鏈?zhǔn)骄幊?- 點(diǎn)式調(diào)用 LinkBlock
為了實(shí)現(xiàn)Objc中的點(diǎn)式調(diào)用, Novo已經(jīng)有了一個(gè)基于block的好玩的實(shí)現(xiàn)LinkBlock。
LinkBlock 旨在幫助我們實(shí)現(xiàn)點(diǎn)方法調(diào)用的happy path。
如:
UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame= CGRectMake(20, 20, 150, 80);
UIColor *color = [UIColor colorWithRed:255/255.0 green:22/255.0 blue:150/255.0 alpha:1.0];
btn.backgroundColor = color;
[btn setTitle:@"click change color" forState:UIControlStateNormal];
[self.view addSubview:btn];
//如果使用鏈?zhǔn)骄幊痰姆绞?,大部分工作可以在思路連續(xù)的情況下進(jìn)行
//now just using one line.Most work can be wrapped up in the idea of ??ongoing cases
btn.viewSetFrame(20,20,150,80).viewBGColor(@"0xff22cc".strToColorFromHexStr())
.viewAddToView(self.view).btnTitle(@"click change color", UIControlStateNormal);
是不是簡潔了許多。
鏈?zhǔn)骄幊?- Masonry
自從iOS設(shè)備尺寸多樣化以后,為了適配大小屏,我們用到了autolayout。
即便是我們使用了VFL,官方的autolayout寫法,在代碼實(shí)現(xiàn)上也過于繁瑣。
所以很大程度上, 一部分人轉(zhuǎn)而重用storyboard界面布局,一部分轉(zhuǎn)而重度依賴mansory, 還有大多數(shù)在結(jié)合使用。
而Masonry的實(shí)現(xiàn)上, 恰恰就是圍繞Maker對象的鏈?zhǔn)骄幊獭?/p>
之前autolayout的代碼是這樣的
UIView *superview = self;
UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view1.backgroundColor = [UIColor greenColor];
[superview addSubview:view1];
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[superview addConstraints:@[
//view1 constraints
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:padding.top],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:padding.left],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:-padding.bottom],
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeRight
multiplier:1
constant:-padding.right],
]];
Masonry實(shí)現(xiàn)、
UIEdgeInsets padding = UIEdgeInsetsMake(10, 10, 10, 10);
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
make.left.equalTo(superview.mas_left).with.offset(padding.left);
make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];
顯而易見的、真是簡潔到?jīng)]朋友。
ps: Masonry 在github上 已有1W+的star。
除了形式上的鏈?zhǔn)秸{(diào)用, Objc中所談的鏈?zhǔn)秸{(diào)用, 更是函數(shù)編程中一種常用的編程手段。
函數(shù)式編程 - Function Chaining
在swift中引入了函數(shù)式編程之后,把函數(shù)編程推到了新的高度。
而在swift中, 偶爾會見到這樣的代碼。
let result = students |> filterOutFailed |> sortByGrade |> formatForPrint |> joinByComma
把 ‘|>’ 換成 ’.' ,便有了極大的相似并不是偶然, 鏈?zhǔn)骄幊?,只是函?shù)編程思想的一種結(jié)合。
百分百的知識 - 實(shí)踐 鏈?zhǔn)骄幊?/h2>
如果團(tuán)隊(duì)有人在項(xiàng)目中,沒有討論的貿(mào)然加入了LinkBlock框架, 我肯定還是會argue一下的。
因過于依賴于LinkBlock,在代碼可讀性上增加了難度,并且增加了不可預(yù)期的崩潰。
如LinkBlock中不能很好的處理,給nil進(jìn)行鏈?zhǔn)秸{(diào)用,造成崩潰。
所以我認(rèn)為,鏈?zhǔn)骄幊谈玫膶?shí)踐,應(yīng)該是應(yīng)用在復(fù)用性較好的組件中, 最好還可以像masonry一樣,使用block包裹起來。
如, 語句塊在objc的使用方式之一:
self.tableView.tableFooterView = ({
UIView *view = [[UIView alloc]initWithFrame:CGRectZero];
view;
});
這不是純秀技巧, 在代碼可讀性上, 他的模塊, 和邏輯更加清晰。
所以我最近在考慮,將鏈?zhǔn)骄幊痰乃枷爰尤胛易约旱?開源項(xiàng)目Router, 或 Dispatcher 中。 而形式上,則更類似Masonry的maker。
場景是 : 假如,我買了一架灰機(jī), 我要駕駛它。
使用Block的特性,Trick實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用
那么,我的飛機(jī),一定可以起飛,降落, 上下左右,依照block的特性。我可以這么實(shí)現(xiàn)它
- (MAFlight *(^)(CGFloat distence))takeOff
{
return ^MAFlight *(CGFloat distence)
{
//Do move distence
return self;
};
}
- (MAFlight *(^)(CGFloat distence))landDown
{
return ^MAFlight *(CGFloat distence)
{
//Do move distence
return self;
};
}
- (MAFlight *(^)(CGFloat distence))forward
{
return ^MAFlight *(CGFloat distence)
{
//Do move distence
return self;
};
}
- (MAFlight *(^)(CGFloat distence))back
{
return ^MAFlight *(CGFloat distence)
{
//Do move distence
return self;
};
}
- (MAFlight *(^)(CGFloat distence))left
{
return ^MAFlight *(CGFloat distence)
{
//Do move distence
return self;
};
}
- (MAFlight *(^)(CGFloat distence))right
{
return ^MAFlight *(CGFloat distence)
{
//Do move distence
return self;
};
}
所以我們就可以這么調(diào)用
MAFlight *flight = [[MAFlight alloc]init];//我買了飛機(jī)
flight.takeOff(10.f).forward(100000.f).left(10.f).right(1.f).back(1.f).back(1.f).landDown(10.f);
好了那么我們已經(jīng)實(shí)現(xiàn)了鏈?zhǔn)秸{(diào)用,但,還沒滿足于此,因?yàn)檫壿嬤€沒有更加清晰。 為了叫買飛機(jī)的流程,和開飛機(jī)的流程更加清晰。實(shí)現(xiàn)了maker、
實(shí)現(xiàn)Maker
為了叫買飛機(jī),我給NSObject實(shí)現(xiàn)了分類+Extra.h
+ (CGFloat)makeFlight:(void (^)(MAFlight *))block {
//購買飛機(jī)
MAFlight *maker = [[MAFlight alloc]init];
//操作飛機(jī)
block(maker);
return maker.distence;
}
再為飛機(jī)加一點(diǎn)語法糖
- (MAFlight *)and
{
return self;
}
所以, 就可以這么玩飛機(jī)了
[objc makeFlight:^(MAFlight *flight){
flight.takeOff(10.f).and.forward(100000.f);
flight.left(10.f).and.right(1.f);
flight.back(1.f).and.back(1.f).landDown(10.f)
}];
OK, That's all.
下一篇 - iOS Nightmare系列之 - 客戶端應(yīng)用的Daily Build 與 持續(xù)化集成(Continuous Integration)