1 什麼是block iOS SDK 4.0開始,Apple引入了block這一特性。字面上說,block就是一個代碼塊,但是它的神奇之處在於在內聯(inline)執行的時候(這和C++很像)還可以傳遞參數。同時block本身也可以被作為參數在方法和函數間傳遞,這就給予了block無限的可能。 對於閉包(block),有很多定義,其中閉包就是能夠讀取其它函數內部變數的函數,這個定義即接近本質又較好理解。對於剛接觸Block的同學,會覺得有些繞,因為我們習慣寫這樣的程式main(){ funA();} funA(){funB();} funB(){.....}; 就是函數main調用函數A,函數A調用函數B... 函數們依次順序執行,但現實中不全是這樣的,例如專案經理M,手下有3個程式員A、B、C,當他給程式員A安排實現功能F1時,他並不等著A完成之後,再去安排B去實現F2,而是安排給A功能F1,B功能F2,C功能F3,然後可能去寫技術文檔,而當A遇到問題時,他會來找專案經理M,當B做完時,會通知M,這就是一個非同步執行的例子。在這種情形下,Block便可大顯身手,因為在專案經理M,給A安排工作時,同時會告訴A若果遇到困難,如何能找到他報告問題(例如打他手機號),這就是專案經理M給A的一個回調介面,要回掉的操作,比如接到電話,百度查詢後,返回網頁內容給A,這就是一個Block,在M交待工作時,已經定義好,並且取得了F1的任務號(局部變數),卻是在當A遇到問題時,才調用執行,跨函數在專案經理M查詢百度,獲得結果後回調該block。 block是一個特殊的OC對象, 它建立在棧上, 而不是堆上, 這麼做一個是為效能考慮,還有就是方便訪問局部變數.預設情況下block使用到的局部變數都會被複製,而不是保留.所以它無法改變局部變數的值.如果在變數面前加上__block, 那麼編譯器回去不會複製變數, 而是去找變數的地址, 通過地址來訪問變數, 實際上就是直接操作變數.另外塊是在棧上分配的, 所以一旦離開範圍, 就會釋放, 因此如果你要把快用在別的地方, 必須要複製一份.所以在屬性定義一個快的時候需要使用copy: @property (nonatomic, copy) void (^onTextEntered)(NSString *enteredText);塊是不能保留的, retain對塊沒有意義. 2 block 實現原理Objective-C是對C語言的擴充,block的實現是基於指標和函數指標。從計算語言的發展,最早的goto,進階語言的指標,到物件導向語言的block,從機器的思維,一步步接近人的思維,以方便開發人員更為高效、直接的描述出現實的邏輯(需求)。iOS中block實現的探究談Objective-C Block的實現 3 block的使用使用執行個體A:cocoaTouch架構下動畫效果的Block的調用動畫效果是IOS介面重要的特色之一,其中CAAnimation是所有動畫對象的抽象父類,作為新人,使用較多的是UIView下的動畫方法(類方法)。使用UIView下的動畫,有下面幾個方法。 方法一:設定beginAnimations 其中memberView為需要添加的子視圖的視圖,mivc.view為子視圖,在使用的時候,需要將這兩個地方替換 需要注意的是,一定要使用[UIView commitAnimations];動畫才會生效 通過[UIView setAnimationDuration:1]; 設定期間。 方法二: 在IOS4.0後,我們有了新的方法,+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion,依然是UIView的類方法,但使用到了Block對象,Block對象是一組指令,可以傳遞(像變數一樣),可以把它想像成C語言的函數指標。 [UIView transitionWithView:self.view duration:0.2 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{ [self.view addSubview:yellowView.view]; } completion:NULL]; B: 使用typed聲明blocktypedef void(^didFinishBlock) (NSObject *ob);這就聲明了一個didFinishBlock類型的block,然後便可用@property (nonatomic,copy) didFinishBlock finishBlock;聲明一個block對象,注意對象屬性設定為copy,接到block 參數時,便會自動複製一份。 __block是一種特殊類型,使用該關鍵字聲明的局部變數,可以被block所改變,並且其在原函數中的值會被改變。C:1 使用block和使用delegate完成委託模式有什麼優點? block不同其它變數的原因在於它不是一個單一變數, 而是一個方法, 我們要傳遞的是一個代碼塊,並且這個代碼塊可以存在參數, 這個參數並不是在定義block的時候就賦予值, 而是我們在實際運行block的時候才賦予值. 因此對於有參數的block,當我們傳遞過去的時候, 它的需要接收方提供相應的參數才能運行, 這麼做我們就可以在A類為B類將來會發生的事件提前做好處理的方法,即使我們還沒有這些事件的具體參數. 某種意義上將這樣就不需要兩者之間的委託關係. 委託關係就是B類發生一個事件後,通知A類,讓A類再針對這個事件進行一些處理 而使用block,則是A已經提前將這個事件的處理方法告訴了B類, 等時間發生的時候, B類無需通知A類, 直接運行實現設定好的處理方法(block)即可. 如果你在運行一個方法的時候又想告訴這個方法在某一特定情況你還要怎麼做的話, 就可以使用Block. D: GCD: GCD主要使用block來代替委託模式,使程式變得簡潔,同時運行效率也得到提高. 複製代碼 static int clickNum = 0; self.Mylabel = [[UILabel alloc]init]; while (clickNum <20) { dispatch_async(dispatch_get_main_queue(), ^{ self.Mylabel.text = [NSString stringWithFormat:@"%d",clickNum++];//UI的繪製必須在主線程中 }); [NSThread sleepForTimeInterval:1]; }複製代碼關於block和GCD編程可以參考這篇文章: 還有這篇文章 ARC和非ARC中block的區別: ARC下Block何時會從棧自動被複製到推, 以及__block和__weak的使用問題 由於Block是預設建立在棧上, 所以如果離開方法範圍, Block就會被丟棄, 在非ARC情況下, 我們要返回一個Block ,需要 [Block copy];在ARC下, 以下幾種情況, Block會自動被從棧複製到堆:1.被執行copy方法2.作為方法傳回值3.將Block賦值給附有__strong修飾符的id類型的類或者Blcok類型成員變數時4.在方法名中含有usingBlock的Cocoa架構方法或者GDC的API中傳遞的時候.對於非ARC下, 為了防止循環參考, 我們使用__block來修飾在Block中實用的對象:__block id blockSelf=self;self.blk=^{NSLog(@"%@",blockSelf); //在非ARC下對於棧上的_block對象, Block不會對其複製, 僅僅使用, 不會增加引用計數.};對於ARC下, 為了防止循環參考, 我們使用__weak來修飾在Block中實用的對象:__weak id weakSelf=self;self.blk=^{NSLog(@"%@",weakSelf);};如果要在ARC下, 為了防止循環參考, 使用__block來修飾在Block中實用的對象,仍然會被retain, 所以需要多做一些設定__block id blockSelf=self;self.blk=^{NSLog(@"%@",blockSelf);self.blk=nil; //blk被釋放, blk只有的blockSelf也就被釋放了};blk(); //並且一定要運行一次, 否則不能被釋放這樣就使blk斷開了與blockSelf的持有關係.這麼多好處是可以自己控制對self的持有時間.不過在最新的ios版本中, 這些會始終被已歎號形式提示存在循環參考問題. 這種書寫方式不被推薦. 除非你要在block中修改__block的指標指向.其實我們用使用__weak修飾符, 只是不能修改對象本身, 但是可以修改對象的屬性.