1、定义一个简单的block:
MJBlock block;
{
MJPerson *person = [[MJPerson alloc] init];
person.age = 10;
block = ^{
NSLog(@"---------%d", person.age);
};
}
NSLog(@"------");
第二个nslog打印完成之后,person不会销毁,因为block有个指针指向了外面的person对象,block在堆上,是malloc类型的。block不销毁,person也不会销毁。但是如果改成mrc环境,栈上的block不会强引用auto对象。但是如果person用__weak修饰的话,person就会先销毁。
上面的block改成下面这样:
MJBlock block;
{
MJPerson *person = [[MJPerson alloc] init];
person.age = 10;
__weak MJPerson *weakPerson = person;
block = ^{
NSLog(@"---------%d", weakPerson.age);
};
}
NSLog(@"------");
这种情况下用之前的clang xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m转变成底层c++代码会报错 cannot create __weak reference in file using manual reference 因为weak是弱引用是在runtime下进行的,所以用xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m转换之后:
typedef void (*MJBlock)(void);
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
MJPerson *__weak person;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, MJPerson *__strong _person, int flags=0) : person(_person) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
MJPerson *__strong person = __cself->person; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_c41e64_mi_0, ((int (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("age")));
}
static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {
_Block_object_assign((void*)&dst->person, (void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
static void __main_block_dispose_0(struct __main_block_impl_0*src) {
_Block_object_dispose((void*)src->person, 3/*BLOCK_FIELD_IS_OBJECT*/);
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0), __main_block_copy_0, __main_block_dispose_0};
之前的MJPerson * person;也转换成了MJPerson *__weak person;
总结如下:
当block内部访问了对象类型的auto变量时
1、如果block是在栈上,不论是强指针还是弱指针都不会去对auto对象进行强引用。
2、如果block被拷贝到堆上。在arc环境下,当一个block被强引用引用着,就会进行copy操作,如果block进行copy操作的时候会调用内部的_Block_object_assign函数 ,调用这个函数会根据外部的auto对象的修饰关键字MJPerson *__weak person或者MJPerson *__strong person对auto进行强引用或者弱引用
3、如果block从堆上移除。会调用block内部的dispose函数,dispose函数内部会调用_Block_object_dispose函数,_Block_object_dispose函数会自动释放引用的auto变量,类似于release操作。
面试题:
MJPerson *p = [[MJPerson alloc] init];
__weak MJPerson *weakP = p;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"1-------%@", p);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"2-------%@", weakP);
});
});
NSLog(@"-----------");
经过nslog1跟nslog2位置的变换,得出一个结论,person的释放时间是看person强引用什么时候释放,不用管弱引用释放