objc利用block實現鏈式編程方法,objcblock鏈式編程

來源:互聯網
上載者:User

objc利用block實現鏈式編程方法,objcblock鏈式編程

objc利用block實現鏈式編程方法

  

  因為不好讀。block和其他語言的匿名函數一樣,很多程式員剛開始很難主動去用他。

  本文描述block作為屬性的實際使用,看懂block,並講解如何利用block實現鏈式編程方法。

  【一】遭遇

  到今天iOS開發中最常用的語言還是objc,市場就像泰坦尼克號,人雖然在上樓,但是船在下沉,所以人還是在下沉。雖然swift出現的迅猛,但是大部分開發人員面對的還是objc。什麼時候swift替代objc,今天的objc開發人員也不用太著急,說不定船都沉了(蘋果保佑)。

  objc最令人頭疼的是他看起來像部落語言一樣的表達。比如下面這行新手代碼,但是就像求偶訊號一樣晦澀:

 [[NSMutableDictionary alloc] initWithContentsOfURL:[NSURL URLWithString:@"a.txt"]][@"persons"][12];

  但它並沒有告訴別人任何有意義的事情,分解一下文法就像下面一樣:

NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithContentsOfURL:[NSURL URLWithString:@"a.txt"]];NSArray* arr = dict[@"persons"];arr[12];

  語言發展到今天,代碼的普世價值不是效率,而是開發效率。這就是為什麼java能夠成為王者的原因。因為java寫起來快,好讀。

  【二】探索

  objc比起java又慢又不好讀。那麼如何讓objc看起來像java一樣呢。縱觀objc全部文法,只有block能夠辦到。我們來看block的定義

returnType  (^name)  (val1, val2, ...); 傳回型別     變數名        參數列表//我們可以從表面認為他是一根指向函數的指標,這個函數的樣子如下(returnType)name(val1, val2, ...){  //......}

  block具有一個函數的外觀,又被當作一個變數。那麼block就具備兩個功能,第一:可以作為類的屬性被'點'出來。第二:可以當作函數直接調用。下面逐個解釋,第一個類的屬性可以點出來,比如person.name;這很好理解,你一定見過,str.length;對吧。第二個呢,block作為一個變數,但是又可以把它當作指向函數的指標一樣調用。

NSString*(^myBlock)() = ^(){ return @"菊樂"; };//定義一個傳回值為NSString類型,無參的,並且名字叫做myBlock的blockmyBlock();//這一行就是調用NSString result = myBlock();//這是取出block執行後拿到的傳回值,也就是@"菊樂"

  這裡再解釋一次block的定義:上面的myBlock可以認為是指向一個定義如下的函數的指標,這個函數是

(NSString*) myBlock(){   //...      }//指向函數的指標NSString* (*p) ();//可以認為指標p就是myBlock(其實block的真實身份更加複雜)

  【三】推理

  我們來幻想一下objc寫起來是這樣的

//設定視圖位置和大小,設定視圖背景色view.setFrame(0,0,50,50).setBackgroundColor( @"#0c0c0c".toColor() );//移除空格並在控制台列印字詩句@" 白 日 依 山 盡 , 黃 河 入 海 流 ".removeStr(@" ").nslog();

  而實際上要寫5行的代碼,一行3秒,3行15秒。就這樣錯過了一次搖一搖的機會,人生在緩慢的艱難,而我們卻還一無所知。

view.frame = CGRectMake(0, 0, 50, 50);view.backgroundColor= [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];    NSString* str= @" 白 日 依 山 盡 , 黃 河 入 海 流 ";str= [str stringByReplacingCharactersInRange:@" " withString:@""];NSLog(str);

  現在我們來倒著分析如何使用block來實現鏈式編程,再來觀察這句話:

view.setFrame(0,0,50,50).setBackgroundColor( @"#0c0c0c".toColor() );

  其中的setFrame和setBackgroundColor他們是什嗎?大家一定知道是屬性。可是屬性是不帶括弧的,setFrame()他是屬性嗎?那他又是什麼呢?setFrame()是屬性,並且是block類型的,因為block可以加括弧調用。就像這樣調用block();那麼還有一個問題很關鍵:view.setFrame().setBackgroundColor();怎麼可以連續點出來,這剛開始很不好理解。這並不難,我們往前看那句話:

NSString result = myBlock();

  細心的去發現,block是可以有傳回值的,那麼我們就依靠這個傳回值就可以點出一堆屬性,一直點下去,這樣我們的鏈式編程的思路就通了。

  【四】實踐

  我們現在就來實現view.setFrame().setBackgroundColor();

  首先準備一個分類。標頭檔定義如下:

//  UIView+Extension.h#import <UIKit/UIKit.h>@interface UIView(Extesion)@property (nonatomic,copy) UIView* (^setFrame)(CGFloat x, CGFloat y, CGFloat w, CGFloat h);@property (nonatomic,copy) UIView* (^setBackgroundColor)(UIColor* color);@end

  我們在UIView類上擴充了兩個額外屬性setFrame和setBackgroundColor,這意味著只要是繼承自UIView的對象就可以點出來這兩個屬性。

  現在我們需要理解一下兩個的區別:

view.setFrame;//這是擷取屬性,它返回一個blockview.setFrame();//這是擷取屬性,它返回一個block,最後我們使用括弧調用了這個block,這個block的傳回值是UIView類型的對象,那麼他就可以繼續點出下一個屬性了

  view.setFrame()這句話的末尾因為加上了括弧所以執行了block,而他的傳回型別是一個UIView對象,所以可以調用setBackgroundColor();

  這裡解釋一下為什麼用copy,block這種類型本來是實值型別的,他本來是在棧上的,在ARC環境下如果被任何強指標過了一次,編譯器就會把他進行一次copy,放到堆記憶體中。block的retain行為預設是用copy的行為實現的,因為block變數預設是聲明為棧變數的,為了能夠在block的聲明域外使用應該使用copy。

   接下來實現.m檔案內的代碼:

- (UIView *(^)(CGFloat, CGFloat, CGFloat, CGFloat))setFrame{    return ?;}

  不難分析出,這個屬性的類型是block,具體是UIView* (^)(CGFloat , CGFloat , CGFloat , CGFloat )類型。那麼‘?’就是這樣一個類型的對象。可是這個對象從哪裡獲得呢,如果是個NSString我還儲存的有,而這個對象只能無從擷取。這並不重要,因為我們並不要要block對象本身,我們需要的是:block對象他能夠執行一些功能就夠了。所以屬性內部返回一個臨時block對象,這個block內部呢去執行一些功能,最重要的是block內部一定要返回UIView類型的對象。編譯器會對block的類型進行苛刻的檢測。

- (UIView *(^)(CGFloat, CGFloat, CGFloat, CGFloat))setFrame{    return ^(CGFloat x, CGFloat y, CGFloat w, CGFloat h){//返回臨時變數的block        self.frame = CGRectMake(x, y, w, h);//block執行一些功能        return self;//block執行完畢的傳回值    };}

  下面是.m檔案的實現

//  UIView+Extension.m#import "UIView+Extension.h"@implementation UIView(Extesion)- (UIView *(^)(CGFloat, CGFloat, CGFloat, CGFloat))setFrame{    return ^(CGFloat x, CGFloat y, CGFloat w, CGFloat h){        self.frame = CGRectMake(x, y, w, h);        return self;    };}- (void)setSetFrame:(UIView *(^)(CGFloat, CGFloat, CGFloat, CGFloat))setFrame{};//該屬性不需要從外部設定,不想警示告就寫空方法- (UIView *(^)(UIColor *))setBackgroundColor{    return ^(UIColor* color){        self.backgroundColor= color;        return self;    };}- (void)setSetBackgroundColor:(UIView *(^)(UIColor *))setBackgroundColor{};@end

  【五】崩潰

  objc中向nil對象發送任何訊息都不會崩潰,但是發送他不能處理的訊息類型就會崩潰,這也是最經常遇到了情況。還有這樣也會崩潰:nil.length; view.length;調用不存在的屬性也會崩潰。那麼這是我們要處理的一個重要的情況。

  試想,一行代碼中間突然有一個處理返回了nil給下一個環節,一調用就崩潰,關鍵是斷點並不能明確告訴你在哪一行。我們只能從控制台中獲得調試資訊。這也是鏈式編程的弊端之一。

  為了處理這種情況,我寫了一個鏈式編程架構LinkBlock來統一處理,針對幾乎所有常用功能進行了鏈式的封裝,並沒有什麼門檻,希望大家幫我點一顆星星,支援天朝做良好的程式員。

  [希望大家幫我點一顆星星]

  【六】效率

  關於效率,肯定比原生低一些,因為多了一次屬性調用,一次一臨時block的建立,一次block的執行。博主的觀點是為了提高開發效率,而降低一些運行效率。有時候也是值得的。

    

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.