可能被忽略掉編程技巧 之 鏈?zhǔn)骄幊?/h2>

可能被忽略掉編程技巧 之 鏈?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)

最后編輯于
?著作權(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)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,286評論 4 61
  • 有很多想法 ,腦子里也有許多構(gòu)思 。為什么不能寫下來?書荒,可以寫自己的小說。從現(xiàn)在開始
    文白__閱讀 236評論 0 0
  • 文|雜家大兵 我不知道大家是否和我一樣是一個(gè)瘋狂收集信息的人,當(dāng)想要了解一個(gè)領(lǐng)域或者一個(gè)行業(yè)的時(shí)候,通常會利用互聯(lián)...
    雜家大兵閱讀 1,080評論 0 3
  • 山下有蕓蕓眾生,萬千燈火山上有飄渺仙人,遺世獨(dú)立2013-5-1 想象你站在山腳的一個(gè)小山坡上,正好可以被風(fēng)吹到,...
    酒笑生閱讀 177評論 0 1

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