ios Block詳細用法

來源:互聯網
上載者:User

ios Block詳細用法
ios4.0系統已開始支援block,在編程過程中,blocks被Obj-C看成是對象,它封裝了一段代碼,這段代碼可以在任何時候執行。Blocks可以作為函數參數或者函數的傳回值,而其本身又可以帶輸入參數或傳回值。它和傳統的函數指標很類似,但是有區別:blocks是inline的,並且它對局部變數是唯讀。

下面是理論部分:

  1、block的定義

 
 1 // 聲明和實現寫在一起,就像變數的聲明實現 int a = 10; 2        int (^aBlock)(int, int) = ^(int num1, int num2) { 3   4        return num1 * num2; 5   6      }; 7 // 聲明和實現分開,就像變數先聲明後實現 int a;a = 10; 8         int (^cBlock)(int,int); 9         cBlock = ^(int num1,int num2)10         {11             return num1 * num2;12         };
 

 

 其中,定義了一個名字為aBlock的blocks對象,並攜帶了相關資訊:

  1、aBlock 有兩個形式參數,分別為int類型;

  2、aBlock 的傳回值為int 類型;

  3、等式右邊就是blocks的具體實現;

  4、^ 帶邊blocks聲明和實現的標示(關鍵字);

當然,你可以定義其他形式的block。e.g:無傳回值,無形式參數等;

1         void (^bBlock)() = ^()2         {3             int a = 10;4             printf(num = %d,a);5         };    

  2、blocks 存取權限

  blocks可以訪問局部變數,但是不能修改。

1         int a = 10;2         int (^dBlock)(int) = ^(int num)3         {4             a++;//not work!5             return num * a;6         };

  此處不能修改的原因是在編譯期間確定的,編譯器編譯的時候把a的值複製到block作為一個新變數(假設是a‘ = 10),此時a'和a是沒有關係的。

這個地方就是函數中的值傳遞。如果要修改就要加關鍵字:__block或者static

 

1         __block int a = 7;2         int (^dBlock)(int) = ^(int num)3         {4             a++;// work!5             return num * a;6         };

  3、block的調用

  block調用就像調用函數一樣。e.g:

1 int c = aBlock(10,10);
  bBlock();

  4、block 應用

  假設我們熟悉代理遞值的話,對代理我們可能又愛有恨!我們先建立模型A頁面 push B頁面,如果把A頁面的值傳遞到B頁面,屬性和單例傳值可以搞定!但是如果Pop過程中把B頁面的值傳遞到A頁面,那就可以用單例或者代理了!說到代理,我們要先聲明協議,建立代理,很是麻煩。常常我們傳遞一個數值需要在兩個頁面間寫很多代碼,這些代碼改變頁面的整體順序,可讀性也打了折扣。所以,此時,block是一種最佳化方案!

5、 block的記憶體管理

 

block本身是像對象一樣可以retain,和release。但是,block在建立的時候,它的記憶體是分配在棧(stack)上,而不是在堆(heap)上。他本身的作於域是屬於建立時候的範圍,一旦在建立時候的範圍外面調用block將導致程式崩潰。比如下面的例子。 我在view did load中建立了一個block:

  1. - (void)viewDidLoad
  2. {
  3. [superviewDidLoad];
  4.  
  5. int number = 1;
  6. _block = ^(){
  7.  
  8. NSLog(@number %d, number);
  9. };
  10. }
並且在一個按鈕的事件中調用了這個block:

  1. - (IBAction)testDidClick:(id)sender {
  2. _block();
  3. }
此時我按了按鈕之後就會導致程式崩潰,解決這個問題的方法就是在建立完block的時候需要調用copy的方法。copy會把block從棧上移動到堆上,那麼就可以在其他地方使用這個block了~ 修改代碼如下:

  1. _block = ^(){
  2. NSLog(@number %d, number);
  3. };
  4.  
  5. _block = [_blockcopy];
同理,特別需要注意的地方就是在把block放到集合類當中去的時候,如果直接把產生的block放入到集合類中,是無法在其他地方使用block,必須要對block進行copy。不過代碼看上去相對奇怪一些:

  1. [array addObject:[[^{
  2. NSLog(@hello!);
  3. } copy] autorelease]];

6、循環參考
對於非ARC下, 為了防止循環參考, 我們使用__block來修飾在Block中使用的對象:
對於ARC下, 為了防止循環參考, 我們使用__weak來修飾在Block中使用的對象。原理就是:ARC中,Block中如果引用了__strong修飾符的自動變數,則相當於Block對該變數的引用計數+1。
這一點其實是在第一點的一個小的衍生。當在block內部使用成員變數的時候,比如

  1. @interface ViewController : UIViewController
  2. {
  3. NSString *_string;
  4. }
  5. @end
在block建立中:

  1. _block = ^(){
  2. NSLog(@string %@, _string);
  3. };
這裡的_string相當於是self->_string;那麼block是會對內部的對象進行一次retain。也就是說,self會被retain一次。當self釋放的時候,需要block釋放後才會對self進行釋放,但是block的釋放又需要等self的dealloc中才會釋放。如此一來變形成了循環參考,導致記憶體泄露。
修改方案是建立一個__block scope的局部變數,並把self賦值給它,而在block內部則使用這個局部變數來進行取值。因為__block標記的變數是不會被自動retain的。

  1. __block ViewController *controller = self;
  2. _block = ^(){
  3. NSLog(@string %@, controller->_string);
  4. };

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.