block对对象变量的捕获
block一般使用过程中都是对对象变量的捕获,那么对象变量的捕获同基本数据类型变量相同吗?
查看一下代码思考:当在block中访问的为对象类型时,对象什么时候会销毁?
typedef void (^Block)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
Block block;
{
Person *person = [[Person alloc] init];
person.age = 10;
block = ^{
NSLog(@"------block内部%d",person.age);
};
} // 执行完毕,person没有被释放
NSLog(@"--------");
} // person 释放
return 0;
}
大括号执行完毕之后,person
依然不会被释放。上一篇文章提到过,person
为aotu
变量,传入的block
的变量同样为person
,即block
有一个强引用引用person
,所以block
不被销毁的话,peroson
也不会销毁。 查看源代码确实如此
将上述代码转移到MRC环境下,在MRC环境下即使block还在,person
却被释放掉了。因为MRC环境下block在栈空间,栈空间对外面的person
不会进行强引用。
//MRC环境下代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
Block block;
{
Person *person = [[Person alloc] init];
person.age = 10;
block = ^{
NSLog(@"------block内部%d",person.age);
};
[person release];
} // person被释放
NSLog(@"--------");
}
return 0;
}
block调用copy操作之后,person不会被释放。
block = [^{
NSLog(@"------block内部%d",person.age);
} copy];
上文中也提到过,只需要对栈空间的block
进行一次copy
操作,将栈空间的block
拷贝到堆中,person
就不会被释放,说明堆空间的block
可能会对person
进行一次retain
操作,以保证person
不会被销毁。堆空间的block
自己销毁之后也会对持有的对象进行release
操作。
也就是说栈空间上的block不会对对象强引用,堆空间的block有能力持有外部调用的对象,即对对象进行强引用或去除强引用的操作。
__weak
__weak添加之后,person
在作用域执行完毕之后就被销毁了。
typedef void (^Block)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
Block block;
{
Person *person = [[Person alloc] init];
person.age = 10;
__weak Person *waekPerson = person;
block = ^{
NSLog(@"------block内部%d",waekPerson.age);
};
}
NSLog(@"--------");
}
return 0;
}
将代码转化为c++来看一下上述代码之间的差别。 __weak修饰变量,需要告知编译器使用ARC环境及版本号否则会报错,添加说明-fobjc-arc -fobjc-runtime=ios-8.0.0
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
__weak修饰的变量,在生成的__main_block_impl_0
中也是使用__weak
修饰。