美文网首页
项目中遇到的 定时器循环引用问题

项目中遇到的 定时器循环引用问题

作者: xxttw | 来源:发表于2023-06-05 23:23 被阅读0次
  • CADidsplayLink & NSTimer
    这两种使用方式 定时器都会强引用target, 从而造成self-> timer -> self循环引用
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(linktest)];
[self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];


这里有的小伙伴可能也会使用    __weak typeof(self) weakSelf = self;
传递给target 但是这样也是不行的, 虽然传递的是weak后指向的弱指针,但是指向的还是target对象的地址,所以还是会产生强引用
self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(linktest) userInfo:nil repeats:YES];
  • 解决方案
  1. NSTimer可以以block的形式使用, block内部使用__weak弱引用self即可
    __weak typeof(self) weakSelf = self;
    self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakSelf linktest];
    }];
  1. 中间对象

继承至NSObject的中间对象

WTProxy 内部 弱引用一个 target对象
timer强引用------> WTProxy弱引用 ------>target
转发消息给target执行aSelector - (id)forwardingTargetForSelector:(SEL)aSelector

@interface WTProxy : NSObject
@property (nonatomic, weak) id target;
+ (WTProxy *)proxyWithTarget:(id)target;
@end

@implementation WTProxy
+ (WTProxy *)proxyWithTarget:(id)target
{
    WTProxy *proxy = [WTProxy alloc];
    proxy.target = target;
    return  proxy;
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return self.target;
}
@end

继承自NSProxy的中间对象

  1. timer强引用 ----> WTProxy1弱引用----> target
  2. 消息转发给target 进行方法签名 - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
  3. 调用- (void)forwardInvocation:(NSInvocation *)invocation
@interface WTProxy1 : NSProxy
@property (nonatomic, weak) id target;
+ (WTProxy1 *)proxyWithTarget:(id)target;
@end

@implementation WTProxy1
+ (WTProxy1 *)proxyWithTarget:(id)target
{
    WTProxy1 *proxy = [WTProxy1 alloc];
    proxy.target = target;
    return proxy;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation invokeWithTarget:self.target];
}

NSObject和NSProxy作为中间对象 它们有什么区别

从上面的示例代码感觉 NSObject来做中间对象好像更加好一点才对啊. (因为只调用forwardingTargetForSelector一个方法) 其实不是原因如下

  • NSObject的中间对象, 它的方法转发流程是 先会通过isa指向的类对象, 从缓存、类、 父类、中进行方法查找, 没有找到进行动态方法解析, 如果没有解析, 才会进入消息转发
  • NSProxy的中间对象, 是直接进入消息转发, 少了从父类进行方法查询(消息发送),少了动态方法解析这里两个阶段, 使用TargetSelector生成方法签NSMethodSignature,然后forwardInvocation 调用方法,即可完成消息转发的流程, 效率比NSObject的会高很多.

相关文章

网友评论

      本文标题:项目中遇到的 定时器循环引用问题

      本文链接:https://www.haomeiwen.com/subject/mgurqdtx.html