什么是Block
block可以理解為匿名函數(shù)(匿名函數(shù):不以文件形式駐留在文件上,生成方式最簡(jiǎn)潔,可以在指令窗或任何函數(shù)體內(nèi)通過(guò)指令直接生成.)
block也可以是一種特殊的數(shù)據(jù)類型,block可以正常定義變量,作為參數(shù),作為返回值,可以保存一段代碼,在需要的時(shí)候調(diào)用.
block常用于GCD,動(dòng)畫,排序以及各類回調(diào)
Block表達(dá)式語(yǔ)法
^返回值類型(參數(shù)列表){ 表達(dá)式 };
例:
^int(int count) {
return count + 1;
};
聲明Block類型變量語(yǔ)法
返回值類型(^變量名)(參數(shù)列表) = Block表達(dá)式
例:
int(^ablock)(int) = ^(int year) {
return year + 1;
};
當(dāng)block類型變量作為函數(shù)參數(shù)時(shí)
- (void)func:(int(^)(int))blk {
NSLog(@"I love you %@ years", blk);
}
// 借助typedef簡(jiǎn)化block
typedef int(^blk)(int);
- (void)func:(blk)blk {
NSLog(@"I love you %@ years", blk);
}
// 1. 聲明一個(gè)block變量
int (^addBlock)(int) = ^(int x) {
return x + 1;
};
// 2. 以block作為函數(shù)參數(shù),把block像對(duì)象一樣傳遞
[self func:addBlock];
// 3. 1與2合并一起,以內(nèi)聯(lián)定義的Block作為函數(shù)參數(shù)
[self func:^(int x) {
return x + 1;
}];
block類型變量作返回值時(shí)
- (int(^)(int))funcReturn {
return ^(int year) {
return year + 1;
};
}
// 借助typedef簡(jiǎn)化block
typedef int(^blk)(int);
- (blk)funcReturn {
return ^(int year) {
return year + 1;
};
}
Blockb內(nèi)存
聲明Block屬性的時(shí)候?yàn)槭裁从胏opy
Block有3種類型
全局塊(NSGlobalBlock)
棧塊(NSStackBlock)
堆塊(NSMallocBlock)
全局塊存儲(chǔ)在靜態(tài)區(qū)(也叫全局區(qū)),
棧塊存儲(chǔ)在棧區(qū),超出作用域則馬上被銷毀
堆塊存儲(chǔ)在堆區(qū)中,是一個(gè)引用計(jì)數(shù)的對(duì)象,需要自行管理其內(nèi)存
怎么判斷block的所在位置呢?
- block不訪問(wèn)外界變量
block既不在棧中也不在堆中,此時(shí)就為全局塊,ARC和MRC下都是如此. - block訪問(wèn)外界變量
MRC環(huán)境下: 訪問(wèn)外界變量的block默認(rèn)存儲(chǔ)在棧區(qū).
ARC環(huán)境下: 訪問(wèn)外界變量的block默認(rèn)存放在堆中,實(shí)際上是先放在棧區(qū),在ARC情況下自動(dòng)又拷貝到堆區(qū),自動(dòng)釋放.
使用copy修飾符的作用就是將block從棧區(qū)拷貝到堆區(qū),從而延長(zhǎng)block的生命周期
例子1:
int testInt = 10;
void (^testBlock)(void) = ^{
NSLog(@"testInt = %d", testInt);
};
testInt = 20;
testBlock();
例子2:
__block int testInt = 10;
void (^testBlock)(void) = ^{
NSLog(@"testInt = %d", testInt);
};
testInt = 20;
testBlock();
在例子1中,block會(huì)把testInt變量復(fù)制為自己私有變量,也就是說(shuō)block會(huì)補(bǔ)貨棧上的變量(或指針),將其復(fù)制為自己私有的const變量.
在例子2中,testInt是一個(gè)局部變量,存儲(chǔ)在棧區(qū)的.給testInt加入__block修飾符所起到的作用就是只要觀察到該變量被block所持有,就將該變量在棧中的內(nèi)存地址存放到堆中,此時(shí)不管block外部還是內(nèi)部testInt的內(nèi)存地址都是一樣的.
Block的循環(huán)引用解決方案
- (void)aBlock {
__weak typeof (self) weakself = self;
self.block = ^{
[weakself doSomething];
};
}
// 但是在并發(fā)執(zhí)行的時(shí)候赐写,block的執(zhí)行是可以搶占的,而且對(duì)weakSelf指針的調(diào)用時(shí)序不同可以導(dǎo)致不同的結(jié)果膜赃,比如在一個(gè)特定的時(shí)序下weakSelf可能會(huì)變成nil挺邀,這個(gè)時(shí)候在執(zhí)行doAnotherThing就會(huì)造成程序的崩潰。為了避免出現(xiàn)這樣的問(wèn)題跳座,采用__strong的方式來(lái)進(jìn)行避免,更改后:
- (void)aBlock {
__weak typeof (self) weakself = self;
self.block = ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf doSomething]; // strongSelf != nil
// 在搶占的時(shí)候端铛,strongSelf還是非nil的。
[strongSelf doAnotherThing];
};
}