iOS循环引用

以下所有内容属笔者原创, 如有雷同纯属巧合, 未经允许不得转载.

这篇内容主要讲解 定时器 中的循环引用, 常见的循环引用和 block 中的循环引用, 解决起来也相对简单, 这里没有介绍, 笔者会在后续更新中陆续补充完整

CDDisplayLinkNSTimer 使用 target 的时候, 容易产生循环引用

  • self 强引用 定时器对象
  • 定时器对象 通过 target 强引用 self

self对象 -> 定时器对象 -> target -> self对象, 从而形成循环引用

解决循环引用的方法:

1. 使用block执行代码块

使用 blcok 的形式来执行代码块, 这样定时器对象就不会强引用 self对象, 这样问题就转化为 block 中的循环引用问题, 可以很方便的解决

2. 加入第三方代理

所有类似的问题, 都可以通过引入一个第三方对象来解决

具体做法(下边用一个 viewController 来指代 self对象):

  1. viewController 强引用 定时器对象
  2. 定时器对象 通过 target 强引用新增的 第三对象
  3. 第三对象 弱引用 viewController

这样虽然三者之间还是 '循环引用', 但是因为 第三对象 弱引用了 viewController, 所以这个循环引用是被打破了的, 不会存在问题

注意

为了保持代码的整体性, 我们同样不会把定时器方法放到 第三对象 中来实现, 依然在 viewController 中实现, 这样我们只需要在 第三对象 中使用 消息转发 就能轻松调用到 viewController 中的定时器方法

更推荐的做法

OC 中并不是所有的类都是继承自 NSObject, 其中有一个类叫做 NSProxy, 他就是专门用来进行消息转发的, 他在执行消息转发的过程中, 效率相对普通 NSObject 对象要高一些

原因是:

不同于普通的 NSObject 对象的方法查找, NSProxy 在当前类的缓存和方法列表中查找方法未果以后, 不会再一次向上, 从他的父类中查找, 而是直接开启消息转发, 因为缺省了这个步骤, 所以他做消息转发的效率会高很多

下面是以上内容的部分代码实现:

HLProxy.h文件部分实现

@interface HLProxy : NSProxy

@property (weak, nonatomic) id target;

+ (instancetype)proxyWith:(id)target;

@end

HLProxy.m文件部分实现

+ (instancetype)proxyWith:(id)target {
    HLProxy *proxy = [HLProxy alloc];
    proxy.target = target;
    return proxy;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}

viewController.m中部分实现

HLProxy *proxy = [HLProxy proxyWith:self];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:proxy selector:@selector(__timerTest) userInfo:nil repeats:YES];

你可能感兴趣的:(iOS循环引用)