對于Block的理解
block是對象挪鹏,它封裝了一段代碼,這段代碼可以在任何時候執(zhí)行愉烙。block可以作為函數(shù)參數(shù)或者函數(shù)的返回值讨盒,而其本身又可以帶輸入?yún)?shù)或返回值。
一.聲明Block變量
返回值(^block名)(參數(shù));
//返回值為int類型參數(shù)為int類型的block
int(^blockName)(int,int);
//返回值為int類型參數(shù)為int類型的block給參數(shù)起名字
int(^blockName)(inta,intb);
//當(dāng)我們需要將block作為函數(shù)參數(shù)時的兩種方式
1.- (void)函數(shù)名:(int(^)(參數(shù)類型1參數(shù)名1,參數(shù)類型2參數(shù)名2))block;
2.typedefint(^myBlock)(參數(shù)類型1參數(shù)名1,參數(shù)類型2參數(shù)名2);
- (void)函數(shù)名:(myBlock)block;
在OC中也可以在.h文件中@property一個block
@property(nonatomic, copy)void(^blockName) (參數(shù)類型*參數(shù)名);
二.實現(xiàn)Block
既然block可以被聲明為變量步责,那么就一定可以實現(xiàn)它返顺,就像其他類型變量的賦值。
對于block可以把它理解成是一斷代碼塊蔓肯,給它賦值便是一段代碼段:
//聲明block
typedefint(^myBlock)(int,int);
@interfaceViewController ()
{
//創(chuàng)建一個myBlock類型的實例對象block1
myBlock block1;
}
@end
@implementationViewController
- (void)viewDidLoad {
[superviewDidLoad];
block1 =^(inta,intb){
returna+b;
};
NSLog(@"%d",block1(1,1));
}
注意:1遂鹊、在上面的代碼里block1是一個對象,如果直接打印將打印對象地址
2省核、block()稿辙,加上后面的括號才是執(zhí)行block語句塊
-----------------------------------------------------------------------------------------------------
三. block訪問對象的微妙關(guān)系
1、如果你在一個block塊中僅僅訪問對象气忠,而不是對他進行修改操作邻储,是沒有任何問題的:
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
inttem=2;
block1 = ^(inta,intb){
intcount= tem+1;
returncount;
};
NSLog(@"%d",block1(1,1));
}
而如果我在block塊中直接修改,編譯器會報錯:
block1 = ^(inta,intb){
tem+=1;//報錯
returntem+1;
};
為什么會出現(xiàn)這樣的情況旧噪,根據(jù)猜測吨娜,可能是block內(nèi)部將訪問的變量都備份了一份,如果我們在內(nèi)部修改淘钟,外部的變量并不會被修改宦赠,我們可以通過打印變量的地址來證明這一點:
- (void)viewDidLoad {
[superviewDidLoad];
inttem=2;
NSLog(@"%p",&tem);
block1 = ^(inta,intb){
NSLog(@"%p",&tem);
returntem+1;
};
NSLog(@"%d",block1(1,1));
}
打印出的地址改變了
// ? ?*所以根據(jù)上面的代碼就可以解釋為什么@property聲明block //的時候要用copy了
// ? ? ? ?block內(nèi)部會把訪問的變量備份一遍
2.__block有什么作用,做了什么?
為了可以在block塊中訪問并修改外部變量,我們常會把變量聲明成__block類型,通過上面的原理勾扭,可以發(fā)現(xiàn)毡琉,其實這個關(guān)鍵字只做了一件事
如果在block中訪問沒有添加這個關(guān)鍵字的變量,會訪問到block自己拷貝的那一份變量妙色,它是在block創(chuàng)建的時候創(chuàng)建的桅滋,而訪問加了這個關(guān)鍵字的變量,則會訪問這個變量的地址所對應(yīng)的變量身辨。我們可以通過代碼來證明:
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
inttem=2;
block1 = ^(inta,intb){
returntem+a+b;
};
tem=4;
NSLog(@"%d",block1(1,1));
block1 = ^(inta,intb){
returntem+a+b;
};
__blockinttem2=2;
tem2=4;
NSLog(@"%d",block1(1,1));
}
運行結(jié)果:4
6
由此丐谋,我們可以理解,如果block中操作的對象是指針煌珊,那么直接可以進行修改号俐,這包括OC對象,如果不是定庵,則需要用__block關(guān)鍵字修飾吏饿。
4、關(guān)于引用計數(shù)
在block中訪問的對象蔬浙,會默認retain:
而添加__block的對象不會被retain;
注意:如果我們訪問類的成員變量找岖,或者通過類方法來訪問對象,那么這些對象不會被retain敛滋,而類對象會被return许布,最常見的時self:
四.關(guān)于block的作用域
應(yīng)避免將花括號中的block用于外面,如果需要绎晃,你可以將這個block聲明為全局的蜜唾。