一胖缤、關(guān)于block在內(nèi)存的位置
Block在內(nèi)存中的位置分三種:
1、NSGlobalBlock:類似函數(shù),位于代碼段(未引用外部變量):
float (^sum)(float, float) = ^(float a, float b){
return a + b;
};
2督怜、NSStackBlock:位于棧內(nèi)存丘跌,函數(shù)返回后block將無效(引用外部變量袭景,但只能在該函數(shù)作用域內(nèi)使用,出作用域該變量內(nèi)存已被釋放闭树,出作用域觸發(fā)block訪問該變量會(huì)Crash):
{
NSArray *testArr = @[@"1", @"2"];
void (^TestBlock)(void) = ^{
NSLog(@"testArr :%@", testArr);
};
NSLog(@"block is %@", ^{
NSLog(@"test Arr :%@", testArr);
});
}
3耸棒、NSMallocBlock:位于堆內(nèi)存(對NSStackBlock 使用copy修飾(strong 應(yīng)該也可以))該類型擁有保存外部變量內(nèi)存的能力。所以調(diào)用外部變量不會(huì)crash,下面將講解對外部變量的存取管理蔼啦。
二榆纽、關(guān)于block外部變量的存取管理
#######在這里只討論ARC機(jī)制下
- (void)test
{
int a = 0;
__block int b = 0;
self.globstring = @"1";
NSString *__localString = @"1";
__block NSString *_blockString = @"1";
printf("a address: %p\n", &a); //a address: 0x7fff56516b3c
printf("b address: %p\n", &b); //b address: 0x7fff56516b30
printf("local address: %p\n", &__localString); //local address: 0x7fff56516b00
printf("_block address: %p\n", &_blockString); //_block address: 0x7fff56516af8
printf("glob address: %p\n", &_globstring); //glob address: 0x7fed5bc09520
void (^TestBlock)(void) = ^{
printf("a value: %d\n", a); //a value: 0
printf("b value: %d\n", b); //b value: 1
printf("b address: %p\n", &b); //b address: 0x60800002a7f8
printf("local address: %p\n", &__localString); // local address: 0x6080000979a0
NSLog(@"lockstring is : %@\n", __localString); //lockstring is : 1
printf("_blcok address: %p\n", &_blockString); //_blcok address: 0x6080000470d8
NSLog(@"_blcokstring is : %@\n", _blockString); //_blcokstring is : 2
printf("globaddress: %p\n", &_globstring); //globaddress: 0x7fed5bc09520
NSLog(@"globstring is : %@\n", _globstring); //globstring is : 2
};
__weak typeof(self) this = self;
self.copyBlock = ^{
printf("a value: %d\n", a); //a value: 0
printf("b value: %d\n", b); // b value: 1
printf("b address: %p\n", &b); // b address: 0x60800002a7f8
printf("copy block local address: %p\n", &__localString); //copy block local address: 0x608000099660
NSLog(@"copy block string is : %@\n", __localString); //copy block string is : 1
printf("_blcok address: %p\n", &_blockString); //_blcok address: 0x6080000470d8
NSLog(@"_blcokstring is : %@\n", _blockString); //_blcokstring is : 2
printf("glob address: %p\n", &_globstring); //glob address: 0x7fed5bc09520
NSLog(@"string is : %@\n", this.globstring); //string is : 2
};
a = 1;
b = 1;
printf("a address: %p\n", &a); //local address: 0x7fff56516b3c
printf("b address: %p\n", &b); //_block address: 0x60800002a7f8
printf("local address: %p\n", &__localString); //local address: 0x7fff56516b00
printf("_block address: %p\n", &_blockString); //_block address: 0x60800002a7f8
__localString = nil;
_blockString = @"2";
self.globstring = @"2";
TestBlock();
self.copyBlock();
}
通過觀察上面的輸出,得出結(jié)論 :
1捏肢、普通的局部變量奈籽,BLOCK聲明時(shí)會(huì)COPY它的值,并且擁有新的地址鸵赫,也就是說block內(nèi)部a 地址和外部a地址不同(如上)衣屏。互不影響辩棒。
2狼忱、__block局部變量,BLOCK聲明時(shí)會(huì)在堆中新建一個(gè)內(nèi)存地址一睁,并且BLOCK之后的所有b 或者 _blockString (如上)都是這個(gè)地址钻弄,所以后續(xù)的讀寫都是再這個(gè)地址上進(jìn)行。會(huì)不想影響者吁。即使不觸發(fā)block 地址也已經(jīng)不是原來的地址窘俺。
3、全局變量 globstring (如上)BLOCK 訪問都是 它本身的地址复凳。直接讀寫操作瘤泪。
4灶泵、BLOCK引用外部對象時(shí)會(huì)強(qiáng)引用外部變量 ,如果該外部變量也強(qiáng)引用BLOCK就會(huì)造成return circle (比如self property block ,block 內(nèi)部訪問self 或者self的屬性)对途,為了解決這個(gè)使用weakSelf赦邻。