一、产生循环引用的原因
//Person.h
typedef void(^Block)(void);
@interface Person : NSObject
@property (nonatomic, copy) Block block;
@end
//main.m
int main(int argc, char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
person.block = ^{
NSLog(@"%@", person);
};
}
return 0;
}
//block底层结构
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
Person *__strong weakPerson; //强引用
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, int flags=0) : person(_person) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
由图可知,person对象强引用block,block强引用person对象,形成循环引用,就这样person对象的内存就一直不能被释放。
二、解决循环引用问题 - ARC
1.用__weak、__unsafe_unretained解决
Person *person = [[Person alloc] init];
__weak typeof(person) weakperson = person;
person.mblock = ^{
NSLog(@"%@", weakperson);
}
Person *person = [[Person alloc] init];
__unsafe_unretained typeof(person) weakperson = person;
person.mblock = ^{
NSLog(@"%@", weakperson);
}
//block底层结构
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
Person *__weak weakPerson; //弱引用
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, int flags=0) : person(_person) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
使用__weak或者__unsafe_unretained创建weakPerson对象,这样block结构体内的成员变量person指针就是一个弱指针,就能使黑色箭头变成虚线。
2.用__block解决(必须要调用block)
__blcok id weakSelf = self;
self.blcok = ^{
NSLog(@"%@", weakSelf);
weakSelf = nil;
};
self.blcok();
因为block执行了,将auto类型的自动变量置为nil,__block变量拥有对象那条线消失了,就打破了循环引用。
网友评论