objective-c - 对 NSTimer 目标的弱引用以防止保留循环

我正在使用这样的 NSTimer:

timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target:self selector:@selector(tick) userInfo:nil repeats:YES];

当然,NSTimer 会保留创建保留循环的目标。此外, self 不是 UIViewController 所以我没有像 viewDidUnload 这样的东西,我可以使计时器无效以打破循环。所以我想知道是否可以改用弱引用:

__weak id weakSelf = self;
timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target:weakSelf selector:@selector(tick) userInfo:nil repeats:YES];

我听说计时器必须无效(我猜是从运行循环中释放它)。但是我们可以在我们的 dealloc 中做到这一点,对吧?

- (void) dealloc {
    [timer invalidate];
}

这是一个可行的选择吗?我见过很多人处理这个问题的方法,但我没有看到这个。

最佳答案

建议的代码:

__weak id weakSelf = self;
timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target:weakSelf selector:@selector(tick) userInfo:nil repeats:YES];

具有以下效果: (i) 对自身进行了弱引用; (ii) 读取弱引用是为了提供指向 NSTimer 的指针。它不会产生创建具有弱引用的 NSTimer 的效果。该代码和使用 __strong 引用之间的唯一区别是,如果在给定的两行之间释放了 self ,那么您会将 nil 传递给计时器。

您能做的最好的事情就是创建一个代理对象。比如:

[...]
@implementation BTWeakTimerTarget
{
    __weak target;
    SEL selector;
}

[...]

- (void)timerDidFire:(NSTimer *)timer
{
    if(target)
    {
        [target performSelector:selector withObject:timer];
    }
    else
    {
        [timer invalidate];
    }
}
@end

然后你会做这样的事情:

BTWeakTimerTarget *target = [[BTWeakTimerTarget alloc] initWithTarget:self selector:@selector(tick)];
timer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:target selector:@selector(timerDidFire:) ...];

或者甚至向 BTWeakTimerTarget 添加一个 +scheduledTimerWithTimeInterval:target:selector:... 形式的类方法,以创建更简洁的代码形式。您可能希望公开真正的 NSTimer 以便您可以 invalidate 它,否则建立的规则将是:

  1. 计时器不会保留真正的目标;
  2. 在真正的目标开始(并且可能已完成)解除分配后,计时器将触发一次,但该触发将被忽略,然后计时器失效。

https://stackoverflow.com/questions/16821736/

相关文章:

objective-c - 从 NSMutableString 中删除最后一个字符

iphone - 以流畅的动画显示/隐藏导航栏

ios - iPhone:在 UITextField 上禁用 Auto-Cap/autocorrec

objective-c - 如何制作真正的私有(private)实例变量?

iphone - 如何将@selector 作为参数传递?

ios - 缩放 UIView 及其所有子项

objective-c - NSMutableArray 按顺序添加对象

objective-c - Xcode 在 iOS 8 的 Main() 中抛出异常,断点为 'al

iphone - 如何在 NSSet 或 NSArray 中搜索具有特定属性的特定值的对象?

c - 什么是双星(例如 NSError **)?