美文网首页
NSTimer的循环引用

NSTimer的循环引用

作者: 小学生课代表 | 来源:发表于2021-06-10 10:43 被阅读0次

    参考

    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self 
    selector:@selector(runTest) userInfo:nil repeats:YES];
    

    此方法会造成循环应用,因为:

    • ViewController 有一个强引用引用着定时器
    • 定时器会对target产生一个强引用
    • 产生了一个循环引用,两个都无法释放了
      解决办法1:iOS10提供的Block的形式的定时器
    __weak typeof(self) weakSelf = self;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 
    repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakSelf runTest];
    }];
    

    解决方法2:使用一个中间介来做消息转发

    (1)、swift版的方法:

    import Foundation
    
    class TimerTarget: NSObject {
    
        weak var target :AnyObject?
        
        convenience init(_ target:AnyObject) {
            self.init()
            self.target = target
        }
        
        override func forwardingTarget(for aSelector: Selector!) -> Any? {
            return target
        }
        
        deinit {
            print("----  deinit ---")
        }
    }
    

    具体使用

    func initTimer()  {
         timer = Timer(timeInterval: 1.0, target: TimerTarget(self), selector: #selector(timerStarted), 
    userInfo: nil, repeats: true)
            RunLoop.current.add(timer!, forMode: .common)
    }
    

    (2)、oc版的方法:
    oc版本使用借助NSProxy这个抽象类,相比NSObject,NSProxy更轻量级, 做消息转发效率更高.必须继承实例化其子类才能使用
    TimerProxy.h文件

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface TimerProxy : NSProxy
    
    - (instancetype)initWithTarget:(id)target;
    
    + (instancetype)proxyWithTarget:(id)target;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    TimerProxy.m文件

    #import "TimerProxy.h"
    
    @interface TimerProxy ()
    
    @property (nonatomic, weak) id target;
    
    @end
    
    @implementation TimerProxy
    
    - (instancetype)initWithTarget:(id)target {
        _target = target;
        return self;
    }
    
    + (instancetype)proxyWithTarget:(id)target {
        return [[TimerProxy alloc] initWithTarget:target];
    }
    
    - (id)forwardingTargetForSelector:(SEL)selector {
        return _target;
    }
    
    @end
    

    具体使用:

    - (void)initTimer {
        TimerProxy * proxy = [TimerProxy proxyWithTarget:self];
        self.timer = [NSTimer timerWithTimeInterval:1.0 target:proxy 
    selector:@selector(timerStart) userInfo:nil repeats:YES];//NSRunLoopCommonModes
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
    }
    

    相关文章

      网友评论

          本文标题:NSTimer的循环引用

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