2021面试专题

iOS之NSTimer循环引用的最佳解决方案

2021-09-09  本文已影响0人  片片碎

最佳方案一:使用新API

如果你的系统只支持iOS10以上,强烈建议使用新API

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block 

这新的API,增加了block的参数。关于这个block参数,官方文档说明如下:

 block  The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references

翻译过来大概意思是:定时器在执行时,讲定时器自身作为参数传递给block,来帮助避免循环引用。使用很简单。只需要注意两点:

#import "SecondViewController.h"
#define WEAKSELF typeof(self) __weak weakSelf = self;
#define STRONGSELF typeof(weakSelf) __strong strongSelf = weakSelf;

@interface SecondViewController ()

@property (nonatomic, strong) NSTimer *timer;

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    WEAKSELF
    self.timer =  [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        STRONGSELF //避免block循环引用
        [strongSelf timerAction];
    }];
}

-(void)viewWillAppear:(BOOL)animated {
    if (self.timer) {
        [self.timer setFireDate:[NSDate distantPast]];
    }
}

- (void)viewWillDisappear:(BOOL)animated {
    if (self.timer) {
        [self.timer setFireDate:[NSDate distantFuture]];
    }
}

- (void)dealloc {
    if (self.timer) {
        [self.timer invalidate]; //dealloc时候从runloop中删除timer
        self.timer = nil;
    }
    NSLog(@"Feng SecondViewController dealloc");
}

-(void)timerAction {
    NSLog(@"Feng timer test");
}
@end

最佳方案二:使用NSProxy

如果实在没有办法,需要兼容10以下版本,那就使用NSProxy吧。SDWebImage就使用了此方案。使用SDWeakProxy这个伪基类,避免timer和target造成循环。此处FengWeakProxy也就相当于SDWebImage中的SDWeakProxy。此方案的好处就是:不需要修改之前的代码,一句都不用修改

代码示范

#import "SecondViewController.h"
#define WEAKSELF typeof(self) __weak weakSelf = self;
#define STRONGSELF typeof(weakSelf) __strong strongSelf = weakSelf;

@interface SecondViewController ()

@property (nonatomic, strong) NSTimer *timer;

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];

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

-(void)viewWillAppear:(BOOL)animated {
    if (self.timer) {
        [self.timer setFireDate:[NSDate distantPast]];
    }
}

- (void)viewWillDisappear:(BOOL)animated {
    if (self.timer) {
        [self.timer setFireDate:[NSDate distantFuture]];
    }
}

- (void)dealloc {
    if (self.timer) {
        [self.timer invalidate]; //dealloc时候从runloop中删除timer
        self.timer = nil;
    }
    NSLog(@"Feng SecondViewController dealloc");
}

-(void)timerAction {
    NSLog(@"Feng timer test");
}
@end
上一篇 下一篇

猜你喜欢

热点阅读