Objective-C中的Block(閉包)

        學習OC有接觸到一個新詞Block(我的感受又是一個牛氣沖天的詞),但不是新的概念,不是新的東西。學過Javascript的小夥伴對閉包應該不陌生吧~學過PHP的應該也不陌生,在PHP5.3版本之後也支持閉包, 也就是OC中所提到的Block。 到底什麼是閉包或者block呢?用大白話說就是匿名函數,也就是在函數中能夠包含這函數。就是在函數中能夠定義匿名函數而後在函數中調用。學習OC中的block以前也小擔憂一下,Block在OC中屬於高級的部分,內心有又有個疑問:學起來難不難?看過Block的部分,感受Block挺好理解的,用起來也挺順手的,Block沒我想象中的那麼難理解。編程

        廢話少說,學習一門新的編程語言是少不了代碼量的支持的,因此代碼是少不了的。下面就通代碼來認識一下OC中的block的使用。閉包

        Block基礎部分app

        1.Block的聲明編程語言

            Block的定義和函數的聲明差很少,就是把函數名改爲(^blockName)便可。下面是block聲明的代碼。函數

            有返回值的學習

1
int  (^sumBlock) ( int int );

            無返回值的 測試

1
void  (^myBlock)( int int );

          2.給block塊賦值spa

 

           給聲明好的block,賦值。block的值就是個函數體,給block塊賦值有兩種方式,一個在聲明的時候賦值,一個是先聲明在賦值。指針

            先聲明再賦值code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//代碼塊的聲明
void  (^myBlock)( int int );
 
//給代碼塊賦值
myBlock = ^( int  a,  int  b)
{
     //test ++;  //報錯
     NSLog(@ "main_test = %d" , test);
 
     //blockVar++不報錯;
     blockVar ++;
     NSLog(@ "blockVar = %d" , blockVar);
 
     int  sum = a + b;
     NSLog(@ "a + b = %d" , sum);
};

            在聲明的時候賦值

1
2
3
4
5
int  (^sumBlock) ( int int ) = ^( int  a,  int  b)
{
     int  sum = a + b;
     return  sum;
};

          3.調用block 

         block的使用和普通函數的使用相同,調用方法以下:

1
2
//調用代碼塊並接收返回值
int  sum = sumBlock(20, 30);

         4.把block當作參數傳入函數

1
2
3
4
5
6
//把代碼塊做爲函數參數
void  blockFunction( int  (^myBlock)( int int ))
{
     int  sum = myBlock(10,20);
     NSLog(@ "fun_sum = %d" , sum);
}  

        5.在代碼塊中使用局部變量和全局變量

            在block中能夠和對全局變量進行訪問和修改,但對局部變量只能夠訪問,若想修改的話,咱們能夠在聲明局部變量的時候加上關鍵字__block

            代碼以下:

1
__block  int  blockVar = 0;

 

        Block進階 參考博客:http://www.cnblogs.com/NarutoYq/

        下面的這些內容是參考上面的博客進一步學習的Block的內容,代碼是參考這上面的博客本身寫的,也就是說下面的東西算是僞原創吧。小夥伴們若是沒大看懂下面的東西,請去上面的博客中進一部的瞭解一下block.

        1.局部變量可變對象和不可變對象在block中的引用

            下面會提供一部代碼,這部分代碼的功能是定義兩個局部變量,一個是可變對象,一個是不可變對象,而後再定義一個Block, 在block中引用兩個局部變量。上面提到了在代碼塊中能夠引用局部變量可是不能夠更改其值,除非在聲明的時候加上__block關鍵字。

            測試代碼以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void  blockTest1()
{
     //定義兩個變量一個是可變的一個是不可變的
     NSString *str1 = @ "str1" ;
     NSMutableString *str2 = [NSMutableString stringWithFormat:@ "str2" ];
 
     //初始值
 
     NSLog(@ "兩個字符串的初始值和初始地址" );
     NSLog(@ "str1 = %@,  str1_p = %p" , str1, str1);
     NSLog(@ "str2 = %@,  str2_p = %p" , str2, str2);
 
 
     //定義block在block中輸出連個變量的值和參數
     void  (^myBlock) () = ^()
     {
         NSLog(@ "******************************************" );
         NSLog(@ "在block塊中輸出局部變量的可變和不可變變量" );
         NSLog(@ "str1 = %@,  str1_p = %p" , str1, str1);
         NSLog(@ "str2 = %@,  str2_p = %p" , str2, str2);
     };
 
     //修改前賦值
     str1 = @ "str1_update" ;
     [str2 appendString:@ "_update" ];
     NSLog(@ "******************************************" );
     NSLog(@ "輸出修改後的值和地址" );
     NSLog(@ "str1 = %@,  str1_p = %p" , str1, str1);
     NSLog(@ "str2 = %@,  str2_p = %p" , str2, str2);
 
     //調用block
     myBlock();
 
     NSLog(@ "******************************************" );
     NSLog(@ "調用block後的值和地址" );
     NSLog(@ "str1 = %@,  str1_p = %p" , str1, str1);
     NSLog(@ "str2 = %@,  str2_p = %p" , str2, str2);
 
 
}

        代碼說明:給定義的各一個可變和不可變的對象一個初始值,而後在調用代碼塊的時候修改兩個局部變量的值,而後再代碼塊中顯示變量的值。

        運行結果以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2014-08-10 13:30:25.710 Memory[1074:303] 兩個字符串的初始值和初始地址
2014-08-10 13:30:25.711 Memory[1074:303] str1 = str1,  str1_p = 0x100005ef0
2014-08-10 13:30:25.712 Memory[1074:303] str2 = str2,  str2_p = 0x100204330
2014-08-10 13:30:25.712 Memory[1074:303] ******************************************
2014-08-10 13:30:25.712 Memory[1074:303] 輸出修改後的值和地址
2014-08-10 13:30:25.713 Memory[1074:303] str1 = str1_update,  str1_p = 0x100005fd0
2014-08-10 13:30:25.713 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330
2014-08-10 13:30:25.713 Memory[1074:303] ******************************************
2014-08-10 13:30:25.714 Memory[1074:303] 在block塊中輸出局部變量的可變和不可變變量
2014-08-10 13:30:25.714 Memory[1074:303] str1 = str1,  str1_p = 0x100005ef0
2014-08-10 13:30:25.714 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330
2014-08-10 13:30:25.714 Memory[1074:303] ******************************************
2014-08-10 13:30:25.715 Memory[1074:303] 調用block後的值和地址
2014-08-10 13:30:25.715 Memory[1074:303] str1 = str1_update,  str1_p = 0x100005fd0
2014-08-10 13:30:25.715 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330

         從上面的輸出結果咱們能夠看到,在代碼塊中輸出的不可變對象是原有的值,而不是咱們改後的值,地址也是初始的地址。而對於可變對象,值是咱們修改後的值,而地址使用原有的地址。若是要想block和不可變局部變量綁定的話,咱們要加上_block

        仍是引用上面博客中的一段話來作一下總結吧:

  1. 對值類型的修改,若是block初始化後,沒法同步到block內部

  2. 對於引用類型的修改,若是block初始化後,修改指針指向,即指向另一塊內存,這樣也是沒法同步到block內部

  3. 對於引用類型的修改,若是block初始化後,對指針指向的內存進行修改,即NSMutableArray add 、remove操做,這樣是能夠用同步到block內部,但block內部一樣沒法修改。

     2.成員變量在block中的使用

    ​    ​成員變量在block中的使用是加上self->a使用的,因此在聲明成員變量的時候加不加__block,在成員函數中的代碼塊中均可以訪問修改;

    ​    ​代碼走起:

    ​    ​interface:

1
2
3
4
5
6
7
8
9
10
@interface BlockTest : NSObject
//聲明兩個成員變量一個用__block 和 不用__block修飾觀察其變化
{
     __block NSString *hasBlock;
     NSString *noBlock;
}
 
-( void )test;
 
@end

    ​方法的實現:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@implementation BlockTest
-( void )test
{
     //分別給兩個成員變量賦初始值
     hasBlock = @ "ludashi" ;
     noBlock = @ "ludashi" ;
     NSLog(@ "hasBlock = %@, hasBlock_p = %p" , hasBlock, hasBlock);
     NSLog(@ " noBlock = %@,  noBlock_p = %p" , noBlock, noBlock);
     
     //定義block
     void  (^myBlock)() = ^()
     {
         //修改加__block的成員變量的值
         hasBlock = @ "ludashi_update" ;
         NSLog(@ "block中輸出的內容" );
         NSLog(@ "hasBlock = %@, hasBlock_p = %p" , hasBlock, hasBlock);
         NSLog(@ " noBlock = %@,  noBlock_p = %p" , noBlock, noBlock);
     };
     
     //改變noBlock的值
     noBlock = @ "ludashi_update" ;
     NSLog(@ "更新後的值" );
     NSLog(@ "hasBlock = %@, hasBlock_p = %p" , hasBlock, hasBlock);
     NSLog(@ " noBlock = %@,  noBlock_p = %p" , noBlock, noBlock);
  
     //調用block
     myBlock();
     
     //調用block後的值
     NSLog(@ "調用myBlock後的值" );
     NSLog(@ "hasBlock = %@, hasBlock_p = %p" , hasBlock, hasBlock);
     NSLog(@ " noBlock = %@,  noBlock_p = %p" , noBlock, noBlock);
}
@end

    ​輸出結果:

1
2
3
4
5
6
7
8
9
10
11
2014-08-10 16:32:42.497 Memory[1349:303] hasBlock = ludashi, hasBlock_p = 0x100006188
2014-08-10 16:32:42.499 Memory[1349:303]  noBlock = ludashi,  noBlock_p = 0x100006188
2014-08-10 16:32:42.499 Memory[1349:303] 更新後的值
2014-08-10 16:32:42.500 Memory[1349:303] hasBlock = ludashi, hasBlock_p = 0x100006188
2014-08-10 16:32:42.500 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828
2014-08-10 16:32:42.500 Memory[1349:303] block中輸出的內容
2014-08-10 16:32:42.501 Memory[1349:303] hasBlock = ludashi_update, hasBlock_p = 0x100006828
2014-08-10 16:32:42.501 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828
2014-08-10 16:32:42.501 Memory[1349:303] 調用myBlock後的值
2014-08-10 16:32:42.502 Memory[1349:303] hasBlock = ludashi_update, hasBlock_p = 0x100006828
2014-08-10 16:32:42.502 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828

總結:

  1. 對於一個、多個成員變量,無論是否用__block修飾(用不用都沒任何影響),block結構體會生成一個成員 :self,而且會引用成員變量所屬的對象實例 self。

  2. 對於成員變量的修改都是經過對象self指針引用來實現的。

  3. block內部對於成員變量的訪問也是經過block結構體對象的成員self 指針引用來實現的。

相關文章
相關標籤/搜索