NSTimer内存管理

时间:2012-11-23 19:10:57

标签: ios nstimer strong-references

执行此代码时:

[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showButtons) userInfo:nil repeats:NO];

我是否需要将其取消或释放它,无论内存管理是什么?

我正在使用ARC

4 个答案:

答案 0 :(得分:31)

是的,NSTimer将保留对target的强引用,这可能会导致(特别是在重复计时器中)强引用周期(例如,保留周期)。但是,在您的示例中,计时器不会重复,并且仅延迟0.5,因此在最坏的情况下,您将拥有一个强大的参考周期,该周期将在0.5秒内自动解决。

但是,未解决的强引用周期的一个常见示例是,UIViewController具有重复的NSTimer属性,但因为NSTimer具有对{{UIViewController的强引用1}},控制器最终会被保留。

因此,如果您将NSTimer保留为实例变量,那么,是的,您应该invalidate来解决强引用周期。如果您只是调用scheduledTimerWithTimeInterval,而不是将其保存到实例变量(正如您可能从您的示例中推断出来的那样),那么当NSTimer完成时,您的强引用周期将得到解决。

顺便说一句,如果您正在处理重复NSTimers,请不要在invalidate所有者的dealloc中尝试NSTimer因为dealloc显然,在强参考周期解决之前,不会调用UIViewController。例如,对于viewDidDisappear,您可以在NSTimer中执行此操作。

顺便说一句,Advanced Memory Management Programming Guide解释了强大的参考周期。显然,这是在他们描述正确使用弱引用的部分,这在这里不适用(因为你无法控制NSTimer使用对目标的强引用这一事实),但它确实很好地解释了强参考周期的概念。


如果您不希望self强烈引用weakSelf,则在macOS 10.12和iOS 10或更高版本中,您可以使用块再现,然后使用{{1模式:

typeof(self) __weak weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:0.5 repeats:false block:^(NSTimer * _Nonnull timer) {
    [weakSelf showButtons];
}];

顺便说一句,我注意到你正在呼叫showButtons。如果您尝试在视图中显示某些控件,则可以完全取消NSTimer的使用并执行以下操作:

self.button1.alpha = 0.0;
self.button2.alpha = 0.0;

[UIView animateWithDuration:0.25
                      delay:0.5
                    options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                 animations:^{
                     self.button1.alpha = 1.0;
                     self.button2.alpha = 1.0;
                 }
                 completion:nil];

这不会遇到NSTimer个对象的保留问题,并且在一个语句中执行延迟以及按钮的优雅显示。如果您在showButtons方法中进行其他处理,则可以将其放在completion块中。

答案 1 :(得分:2)

如果你将它保存在属性中,那么是的,你需要在它触发选择器后将其设置为nil。

保存它也是安全的,以防你的课程由于某种原因被解除分配,以便你可以[timer invalidate](如果需要)。

答案 2 :(得分:1)

是的,您可以使用:myTimer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showButtons) userInfo:nil repeats:NO]; 然后在你的viewDidDisappear [myTimer invalidate]

答案 3 :(得分:1)

使用使用闭包的Timer新方法

val enumerator = Enumerator.outputStream { os =>
          val zip = new ZipOutputStream(os);
          zip.putNextEntry(new ZipEntry("test.txt"))

          Range(0, 100).map { i =>
           zip.write("Here are 100000 random numbers:\n".map(_.toByte).toArray)

          }
          zip.closeEntry()
          zip.close()
        }
    Ok.chunked(enumerator >>> Enumerator.eof)
.withHeaders("Content-Type"->"application/zip" ,
"Content-Disposition"->"attachment; filename=test.zip")