23·iOS 面试题·描述一个 retain cycle 例子

前言

这个题目就比较简单了,在平时开发中,总是会遇到循环引用的问题,这里我们先聊一下为什么会出现循环引用,然后再列举 Block 和 Delegate 是如何出现循环引用以及如何避免。

循环引用的原因

首先我们知道 Objective-C 是利用引用计数机制来进行内存管理而不是垃圾回收,引用计数机制其中一个缺点就是不能自动解决循环引用的问题,需要我们手动处理。

简单来说,每个对象都有一个与之对应的引用计数值,只有当引用计数值为 0 的时候,该对象才会被系统回收。当对象 A 强引用对象 B,对象 B 又强引用了对象 A,这样子对象 A 和 对象 B,它们的引用计数值都不会为 0,即它们都不会被系统回收,这里就出现了循环引用了。

Delegate 出现循环引用例子 & 解决方案

例子:

Person:
@property (nonatomic, strong) id delegate;

self.person = [Person new];
self.person.delegate = self;

// self 强引用了 person
// self.person.delegate = self; -> person 强引用了 self
// 这里就出现了循环引用

解决方案:

Person:
@property (nonatomic, weak) id delegate;

self.person = [Person new];
self.person.delegate = self;

// self 强引用了 person
// self.person.delegate = self; -> person 弱引用了 self
// 这里不会出现循环引用

Block 出现循环引用例子 & 解决方案

@property (nonatomic, copy) void (^myBlock)();

self.myBlock = ^{
        self;
});
// self 强引用了 myBlock
// myBlock 截获了self -> 即 myBlock 强引用了 self
// 这里就出现了循环引用

解决方案:

@property (nonatomic, copy) void (^myBlock)();

__weak typeof(self)weakSelf = self;
self.myBlock = ^{
        weakSelf;
});
// self 强引用了 myBlock
// myBlock 截获了 weakSelf -> 即 myBlock 弱引用了 self
// 这里不会出现循环引用

Block 还有种特殊情况,在执行 Block 时候,self 可能会被释放了,所以我们需要在 Block 内部对 self 进行强引用,确保在执行 Block 期间,self 不会被释放:

@property (nonatomic, copy) void (^myBlock)();

__weak typeof(self)weakSelf = self;
self.myBlock = ^{
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        strongSelf;
});

总结

只要明白了对象之间持有关系,还是比较容易避免循环引用的问题。

你可能感兴趣的:(23·iOS 面试题·描述一个 retain cycle 例子)