學習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
仍是引用上面博客中的一段話來作一下總結吧:
對值類型的修改,若是block初始化後,沒法同步到block內部
對於引用類型的修改,若是block初始化後,修改指針指向,即指向另一塊內存,這樣也是沒法同步到block內部
對於引用類型的修改,若是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
|
總結:
對於一個、多個成員變量,無論是否用__block修飾(用不用都沒任何影響),block結構體會生成一個成員 :self,而且會引用成員變量所屬的對象實例 self。
對於成員變量的修改都是經過對象self指針引用來實現的。
block內部對於成員變量的訪問也是經過block結構體對象的成員self 指針引用來實現的。