(一)copy
ARC環(huán)境下,編譯器會(huì)根據(jù)情況自動(dòng)將stackblock進(jìn)行copy操作,復(fù)制到堆上
- block作為函數(shù)返回值時(shí)
- 將block賦值給__strong指針時(shí)
- block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時(shí)
- block作為GCD API的方法參數(shù)時(shí)
//1 2 示例省略
//block作為GCD API的方法參數(shù)時(shí)
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
ZQPerson *person = [[ZQPerson alloc] init];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"---------- %@",person);
});
}
//block作為Cocoa API中方法名含有usingBlock的方法參數(shù)時(shí)
NSArray *array = @[@(5), @(8), @(10)];
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%d %@",idx,obj);
}];
(1)block屬性的常用寫法(copy strong進(jìn)行強(qiáng)引用)
MRC下block屬性的建議寫法
@property (copy, nonatomic) void (^block)(void);ARC下block屬性的建議寫法
@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);
(2) block內(nèi)部訪問對象類型的auto變量
block是在棧上(stackBlock),將不會(huì)對auto變量產(chǎn)生強(qiáng)引用
block被拷貝到堆上
- 會(huì)調(diào)用block內(nèi)部的copy函數(shù)
- copy函數(shù)內(nèi)部會(huì)調(diào)用
_Block_object_assign
函數(shù) -
_Block_object_assign
函數(shù)會(huì)根據(jù)auto變量的修飾符(__strong、__weak、__unsafe_unretained
)做出相應(yīng)的操作,形成強(qiáng)引用(retain)或者弱引用
- 如果block從堆上移除
- 會(huì)調(diào)用block內(nèi)部的dispose函數(shù)
- dispose函數(shù)內(nèi)部會(huì)調(diào)用
_Block_object_dispose
函數(shù) -
_Block_object_dispose
函數(shù)會(huì)自動(dòng)釋放引用的auto變量(類似release
,斷開block對變量的持有)
block內(nèi)部訪問對象類型的auto類型的變量①
block內(nèi)部訪問對象類型的auto類型的變量②
(二)weak
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
ZQPerson *person = [[ZQPerson alloc] init];
__weak ZQPerson *weakPerson = person;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"---------- %@",weakPerson);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"---------- %@",person);
});
});
}
//輸出結(jié)果:
/*block對weakPerson弱引用,但是因?yàn)楹竺娴膒erson變量被強(qiáng)引用,所以person還沒有被釋放
---------- <ZQPerson: 0x60000189c7b0>
---------- <ZQPerson: 0x60000189c7b0>
dealloc
*/
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
ZQPerson *person = [[ZQPerson alloc] init];
__weak ZQPerson *weakPerson = person;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"---------- %@",person);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"---------- %@",weakPerson);
});
});
}
//輸出結(jié)果:
/*person變量被強(qiáng)引用,后面的block對weakPerson弱引用,此時(shí)person已被釋放
---------- <ZQPerson: 0x6000005c3eb0>
dealloc
---------- (null)
*/
通過上面的兩個(gè)代碼。我們可以看到結(jié)果不同
在使用clang轉(zhuǎn)換OC為C++代碼時(shí),可能會(huì)遇到以下問題
cannot create __weak reference in file using manual reference
解決方案:支持ARC、指定運(yùn)行時(shí)系統(tǒng)版本,比如:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-9.0.0 main.m
(三)__block
(1)block修改變量
- 在block內(nèi)部修改auto類型的變量是報(bào)錯(cuò)的
- 在block內(nèi)部可以修改static類型的變量,但是永久在內(nèi)存中
-
在block內(nèi)部可以修改全局變量
image.png
如何將在block內(nèi)部修改auto類型的變量呢?__block
__block int age = 10;
ZQBlock block = ^{
age = 20;
NSLog(@"%d",age);
};
block();
(2)__block的本質(zhì)
- __block可以用于解決block內(nèi)部無法修改auto變量值的問題
- __block不能修飾全局變量、靜態(tài)變量(static)
- 編譯器會(huì)將__block變量包裝成一個(gè)對象
__block的底層結(jié)構(gòu)
改值
疑問(1):如果auto變量是對象?
如果是對象,則會(huì)多兩個(gè)函數(shù)
疑問(2):如果block內(nèi)部操作對象屬性/方法?
//不需要使用__block 能不加就不加 因?yàn)闀?huì)被多包裝一層
NSMutableArray *array = [NSMutableArray array];
ZQBlock block = ^{
[array addObject:@"123"];
};
block();
疑問(3):如下面的代碼,block調(diào)用完后,繼續(xù)訪問age、person變量,他們的地址存放在哪里?
__block int age = 10;
__block ZQPerson *person = [[ZQPerson alloc] init];
NSLog(@"1 %d %p %@",age,&age, person);
ZQBlock block = ^{
age = 20;
person = [[ZQPerson alloc] init];
NSLog(@"2 %d %p %@",age,&age, person);
};
block();
NSLog(@"3 %d %p %@",age,&age, person);
/*輸出結(jié)果:
1 10 0x7ffeefbff558 <ZQPerson: 0x100508850>
2 20 0x1005093b8 <ZQPerson: 0x1005093f0>
3 20 0x1005093b8 <ZQPerson: 0x1005093f0>
*/
答:訪問的age和person其實(shí)是block創(chuàng)建的對象中的age與person