下面代码是否会循环引用
DXPerson *person = [[DXPerson alloc] init];
person.age = 10;
person.block = ^{
NSLog(@"age = %d", person.age);
};
答:会,编译器已经有提示
如何修改,才不会循环引用?
1.使用__weak
DXPerson *person = [[DXPerson alloc] init];
person.age = 10;
__weak DXPerson *weakPerson = person;
person.block = ^{
NSLog(@"age = %d", weakPerson.age);
};
或者使用typeof()
// typeof(person) == DXPerson *
// 好处就是不需要知道person到底是什么类型
__weak typeof(person) weakPerson = person;
经常可以看到weakSelf
__weak typeof(self) weakSelf = self;
2.使用__unsafe_unretained
这个关键字解决循环引用
__unsafe_unretained DXPerson *weakPerson = person;
// 或
// __unsafe_unretained typeof(person) weakPerson = person;
__unsafe_unretained
和__weak
的区别
__unsafe_unretainerengd
是不安全的,不会产生强引用,因为指向的对象释放后,指针仍然指向原来的地址,如果又使用到了这个指针,就会出现野指针,因此ARC环境下,不常用,多用于MRC环境上.
__weak
是安全的,不会产生强引用,对象释放后,指针自动置为nil(MRC环境上,是没有__weak
弱引用)
3.使用__block
这个关键字解决循环引用
__block DXPerson *person = [[DXPerson alloc] init];
person.age = 10;
person.block = ^{
NSLog(@"age = %d", person.age);
// 使用`__block`修饰对象,那么这个对象就可以修改了,否则下面编译器会报错
person = nil;
};
person.block();
必须调用block
和person = nil
,两者缺一不可.这种方案不推荐
查看C++中block代码,这个block中有person这个对象
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__Block_byref_person_0 *person; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_person_0 *_person, int flags=0) : person(_person->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
查看person
这个__Block_byref_person_0
结构体
struct __Block_byref_person_0 {
void *__isa;
__Block_byref_person_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
DXPerson *__strong person;
};
可以看到这个结构体有__strong
修饰的person对象
如图
在MRC环境上使用__unsafe_unretained
或者__block
__unsafe_unretained DXPerson *person = [[DXPerson alloc] init];
//__block DXPerson *person = [[DXPerson alloc] init];
person.age = 10;
person.block = ^{
NSLog(@"age = %d", person.age);
};
person.block();
[person release];
在MRC环境上__unsafe_unretained
或者__block
都用来告诉编译器,不要对对象进行retain
操作,因此相当于弱引用
面试题:
1.在block内部NSMutableArray
添加或者删除元素,是否需要添加__block
进行修饰?
DXPerson *person = [[DXPerson alloc] init];
NSMutableArray *array = [NSMutableArray array];
person.block = ^{
[array addObject:@1];
};
答案:不需要,除非在block内部array = nil
才需要
2.声明block时候,使用copy还是strong?
@property (nonatomic,strong) DXBlock block;
@property (nonatomic,copy) DXBlock block;
在ARC环境上答案是一样,因为在ARC环境上,strong
或者copy
都会对block
进行copy
操作,保证block
拷贝到堆上.
在MRC环境上,strong
不会对block
进行copy
操作,copy
会对block
进行copy
操作,保证block
拷贝到堆上.