從上些章節(jié)block-變量的捕獲(caputer)中,詳細說了基本類型的auto變量的捕獲绍填,現(xiàn)在來了解下,對象類型的auto變量是怎樣捕獲和底層結(jié)構(gòu)是如何的滔驶。
block自動copy的情況
在ARC環(huán)境下卿闹,編譯器會根據(jù)情況自動將棧上的block復制到堆上,比如以下情況
-
block
作為函數(shù)返回值時 -
block
賦值給__strong
指針時 -
block
作為Cocoa API
中方法名含有usingBlock
的方法參數(shù)時 -
block
作為GCD API
的方法參數(shù)時
#import <Foundation/Foundation.h>
#import "RMPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
RMPerson *person = [[RMPerson alloc] init];
person.age = 20;
void (^block)(void) = ^ {
NSLog(@"age is %d",person.age);
};
[person release];
NSLog(@"-----------");
}
return 0;
}
----------------- RMPerson.h -----------------
#import <Foundation/Foundation.h>
@interface RMPerson : NSObject
@property (nonatomic, assign) int age;
@end
----------------- RMPerson.m -----------------
#import "RMPerson.h"
@implementation RMPerson
- (void)dealloc {
[super delloc];
NSLog(@"RMPerson-delloc");
}
@end
// MRC 環(huán)境 控制臺輸出
2018-07-03 10:34:39.523223+0800 __block的本質(zhì)[20912:1898201] RMPerson-delloc
2018-07-03 10:36:17.021712+0800 __block的本質(zhì)[20912:1898201] -----------
Program ended with exit code: 0
留意上面代碼插佛,是在MRC的環(huán)境下的代碼量窘,當NSLog(@"-----------");
打印前了,RMPerson就釋放了,什么原因呢嫩海?雖然block訪問的是對象類型的auto變量
囚痴,但還是訪問了auto變量,所以block是屬于NSStackBlock奕谭,是存在棧空間的血柳,block運行完就會釋放生兆,它自己都不知道自己能存活多久,所以是不會作強持有RMPerson的操作鸦难。(結(jié)論一:如果block是在棧上,將不會對auto變量產(chǎn)生強引用)
#import <Foundation/Foundation.h>
#import "RMPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
RMPerson *person = [[RMPerson alloc] init];
person.age = 20;
void (^block)(void) = [^ {
NSLog(@"age is %d",person.age);
} copy]; // copy操作击敌,從棧中復制到堆中
[person release];
NSLog(@"-----------");
}
return 0;
}
----------------- RMPerson.h -----------------
#import <Foundation/Foundation.h>
@interface RMPerson : NSObject
@property (nonatomic, assign) int age;
@end
----------------- RMPerson.m -----------------
#import "RMPerson.h"
@implementation RMPerson
- (void)dealloc {
[super delloc];
NSLog(@"RMPerson-delloc");
}
@end
// MRC 環(huán)境 控制臺輸出
2018-07-03 10:49:35.425698+0800 __block的本質(zhì)[21020:1916302] -----------
Program ended with exit code: 0
從上面的控制臺輸出可以看出沃斤,即使程序結(jié)束了挤聘,RMPerson都沒有釋放捅彻,這是為什么呢组去? 因為block做了copy操作步淹,從棧中拷貝到了堆中,此時block強引用了RMPerson键闺,所以保住了RMPerson澈驼。
下面我們來看一下,底層c++代碼是如何堆中的block是如何保住RMPerson的。
對象類型的auto變量
從上面源碼分析徘六,
如果block被拷貝到堆上時
- 1.會調(diào)用block內(nèi)部的copy函數(shù)
- 2.copy函數(shù)內(nèi)部會調(diào)用_Block_object_assign函數(shù)
- 3._Block_object_assign函數(shù)會根據(jù)auto變量的修飾符(__strong榴都、__weak、__unsafe_unretained)做出相應的操作竿音,形成強引用(retain)或者弱引用拴驮。
如果block從堆上移除
- 1.會調(diào)用block內(nèi)部的dispose函數(shù)
- 2.dispose函數(shù)內(nèi)部會調(diào)用_Block_object_dispose函數(shù)
- 3._Block_object_dispose函數(shù)會自動釋放引用的auto變量(release)
block copy
總結(jié):
當block內(nèi)部訪問了對象類型的auto變量時
1.如果block是在棧上,將不會對auto變量產(chǎn)生強引用
2.如果block被拷貝到堆上
- 會調(diào)用block內(nèi)部的copy函數(shù)
- copy函數(shù)內(nèi)部會調(diào)用_Block_object_assign函數(shù)
- _Block_object_assign函數(shù)會根據(jù)auto變量的修飾符(__strong快鱼、__weak纲岭、* __unsafe_unretained)做出相應的操作,形成強引用(retain)或者弱引用
3.如果block從堆上移除
- 會調(diào)用block內(nèi)部的dispose函數(shù)
- dispose函數(shù)內(nèi)部會調(diào)用_Block_object_dispose函數(shù)
- _Block_object_dispose函數(shù)會自動釋放引用的auto變量(release)