下面的講解均是在MRC下進(jìn)行,首先,需設(shè)置-fno-objc-arc。
兩概念
- 堆
內(nèi)存需要手動(dòng)分配(malloc)和銷毀(free)。 - 棧
一個(gè)線程會(huì)分配一個(gè)stack,里面包含這個(gè)函數(shù)參數(shù),局部變量,返回地址等信息。當(dāng)函數(shù)返回后,棧會(huì)被銷毀,有系統(tǒng)操作。 后面再去retain和copy是無效的。
棧對(duì)象有速度的優(yōu)勢(shì),不會(huì)發(fā)生內(nèi)存泄漏,
存儲(chǔ)區(qū)域
通過查看block的isa值,可以看到以下3個(gè)名詞:
- NSGlobalBlock 全局
- NSStackBlock 棧
- NSMallocBlock 堆
代碼演示
//全局block
- (dispatch_block_t)testGlobalBlock {
dispatch_block_t block = ^(){
NSLog(@"global block");
};
return block;
//或
// return [block copy];//仍是全局
}
//棧block
- (dispatch_block_t)testStackBlock {
__block NSInteger i = 0;
dispatch_block_t block = ^() {
NSLog(@"%ld", ++i);
};
return block;
}
dispatch_block_t block = [self testStackBlock];
block(); 會(huì)crash
dispatch_block_t copyBlock = [block copy];
copyBlock(); 依然crash
//堆 block
- (dispatch_block_t)testMallocBlock {
__block NSInteger i = 0;
dispatch_block_t block = ^() {
NSLog(@"%ld", ++i);
};
return [block copy];
}
- 全局,不訪問外部任何變量,copy后仍是全局block;
- 棧,block里有訪問外部變量,函數(shù)返回后立即銷毀,即使后面strong和copy都會(huì)crash;
- 堆,有棧block拷貝過來,就和OC對(duì)象一樣,可訪問外部變量;
block為什么不用strong
@property (nonatomic, strong) NSString *testStr;
@property (nonatomic, strong) dispatch_block_t strongBlock;
testStr = @"aaa";
- (void)testStackBlock {
__block NSInteger i = 0;
//注意此處是self.而不是_strongBlock
self.strongBlock = ^() {
NSLog(@"%ld", ++i);
NSLog(@"%@", _testStr);
};
self.copyBlock = ^() {
NSLog(@"%ld", ++i);
NSLog(@"%@", _testStr);
};
}
[self testStackBlock];
_strongBlock(); //堆
_copyBlock(); //堆
棧blog不能訪問全局對(duì)象,只有堆blog。因?yàn)閟trong和copy均是copy,從語(yǔ)義上更貼切
ARC
在ARC下,即使你聲明的修飾符是strong,實(shí)際上效果是與聲明為copy一樣的。因此在ARC情況下,創(chuàng)建的block仍然是NSStackBlock類型,只不過當(dāng)block被引用或返回時(shí),ARC完成了copy和內(nèi)存管理的工作。