【问题标题】:Memory management of NSTimer -- does it need to be assigned to a variable?NSTimer 的内存管理——是否需要分配给变量?
【发布时间】:2011-10-02 17:40:48
【问题描述】:

每当我想制作计时器时,我都会这样做:

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

而不是

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 
                                                  target:self 
                                                selector:@selector(someMethod) 
                                                userInfo:nil 
                                                 repeats:NO];

第一个是内存泄漏吗?使用它们的正确方法是什么?

【问题讨论】:

    标签: objective-c cocoa memory-leaks nstimer foundation


    【解决方案1】:

    你在任一sn-p中都没有内存问题;您只需选择与计时器交互的需求即可。

    当您安排一个计时器时,运行循环会保留它,并且在它触发并使用它的选择器时传递对计时器的引用——例如,(void) doTimerThing: (NSTimer *)tim1——因此,您不必严格将其放入变量中并自己保留。 Apple 在 Timer Programming Topics 文档的 "Memory Management" section 中非常清楚地解释了这一点。

    但是,如果您可能希望在计时器触发之前(或在重复计时器的触发之间)使计时器无效,则您确实需要对其进行引用。在这种情况下,调用retain 也是一个好主意。 scheduledTimerWithTimeInterval:target:... 方法返回一个不属于你的对象,你不应该对不属于你的对象的内存状态做出假设(包括它们是否在自动释放池中,或者运行循环的时间长短)将保持计时器)。如果您需要计时器(或任何对象)保持不变,您应该通过调用 retain 来声明对它的所有权。


    1 请注意,计时器的方法应始终为have one parameter;你的 sn-p 中的选择器看起来像是一个没有的方法。计时器似乎以这种方式工作,但您的操作与记录的界面相反。

    【讨论】:

    • 什么意思应该总是只有一个参数?
    • 查看我包含的 sn-p 并阅读链接的文档。计时器的方法需要能够接受一个参数,NSTimer 的实例。
    【解决方案2】:

    除了前面的答案,如果不需要重复计时器,可以使用

    [self performSelector:@selector(someMethod) withObject:nil afterDelay:5.0];
    

    而不是手动创建计时器。

    【讨论】:

    • 这样做有什么好处吗?
    • @mohabitar:这会在幕后创建一个计时器,这是一种更直接、或许更易读的方法,可以将方法的执行延迟一段时间。
    【解决方案3】:

    无论哪种方式,都没有内存泄漏。第二种解决方案只是将结果影响到一个变量,而第一种不存储结果,但效果是一样的。

    正如命名约定所暗示的,给定方法的名称scheduledTimerWithTimeInterval:...,您知道它将返回一个自动释放的对象(或者更准确地说,它将返回一个您不是所有者的对象,并且您不必自己向其发送版本)

    如果不需要,您不必保留对创建的NSTimer 的引用:计时器将安排在 RunLoop 上(即 RunLoop 将保留它直到使用它,并在完成时释放它,所以你不必费心),所以它会自己生活。

    但是如果您不将返回的NSTimer 存储在第二个代码中的变量中,那么您将无法取消计时器,如果您愿意的话。特别是,如果你设置了一个重复计时器,你需要将它存储在一个变量中,以便你以后可以访问它,特别是向它发送一个invalidate 消息以便它可以被取消。

    【讨论】:

    • scheduledTimerWithTimeInterval: not 返回一个自动释放的对象;它返回一个不属于调用者的对象。
    • 是的,但是如果您阅读了我的编辑,我解释了(以及在其他评论中)我的真正意思并给出了我的意思的所有精确度(如果您仔细阅读,我已经解释过甚至在我编辑 RunLoop 保留计时器之前)
    • 一个在自动释放池中的对象仍然可以被其他对象拥有,一个不被调用者拥有的对象不必在自动释放池中。它们是一回事,不应混为一谈。
    • 更重要的是,在 Instruments 对该对象的历史之外,一个对象是否曾经被自动释放是不值得考虑的。唯一重要的问题是,你拥有它吗?
    猜你喜欢
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    • 2015-10-13
    • 1970-01-01
    • 2011-01-26
    相关资源
    最近更新 更多