NSTimer的内存管理——是否需要分配给变量?
每当我想制作一个计时器时,我都会这样做:
[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];
第一个是内存泄漏吗?使用它们的正确方法是什么?
Whenever I want to make a timer, I just do:
[NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(someMethod)
userInfo:nil
repeats:NO];
rather than
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(someMethod)
userInfo:nil
repeats:NO];
Is the first one a memory leak? What's the correct way to use them?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
任何一个片段都没有记忆问题;您只需选择与计时器交互的需求即可。
当您安排计时器时,运行循环会保留它,并且在计时器触发时传递对计时器的引用及其选择器 - 例如,
(void) doTimerThing: (NSTimer *)tim
1 - 已使用,因此您严格没有必要将其放入变量中并自己保留它。苹果在 定时器编程主题文档的“内存管理”部分。但是,如果您可能希望在计时器触发之前(或在重复计时器触发之间)使计时器无效,那么您确实需要对其进行引用。在这种情况下,对其调用
retain
也是一个好主意。scheduledTimerWithTimeInterval:target:...
方法返回一个不属于您的对象,并且您不应该假设不属于您的对象的内存状态(包括它们是否处于自动释放状态)是否有池,或者运行循环将保持计时器多长时间)。如果您需要计时器(或任何对象)保留下来,您应该通过调用retain
来声明其所有权。1 请注意,计时器的方法应始终只有一个参数;代码片段中的选择器看起来像是用于不支持的方法。计时器似乎是这样工作的,但您的操作与记录的界面相反。
You have no memory problem in either snippet; you simply have to make a choice about your needs for interacting with the timer.
When you schedule a timer, the run loop retains it, and a reference to the timer is passed along when it fires and its selector -- e.g.,
(void) doTimerThing: (NSTimer *)tim
1 -- is used, so it isn't strictly necessary for you to put it into a variable and retain it yourself. Apple explains this pretty clearly in the "Memory Management" section of the Timer Programming Topics doc.If, however, you might want to invalidate the timer before it fires (or in between fires for a repeating timer), you do need to have a reference to it. In that case, it is also a good idea to call
retain
on it. ThescheduledTimerWithTimeInterval:target:...
method returns an object that you do not own, and you should not make assumptions about the memory status of objects you don't own (including whether they are in an autorelease pool or not, or how long the run loop is going to keep the timer around). If you need the timer (or any object) to stick around, you should make a claim of ownership on it by callingretain
.1 Note that a timer's method should always have one parameter; the selector in your snippet looks like it is for a method that does not. The timer seems to work that way, but you're operating contrary to the documented interface.
除了前面的答案之外,如果您不需要重复计时器,您可以使用
而不是手动创建计时器。
In addition to previous answers, if you don't need repeating timer, you can use
instead of creating timer manually.
无论哪种方式,都不存在内存泄漏。第二种解决方案只是将结果影响到变量,而第一个解决方案不存储结果,但效果是相同的。
正如命名约定所示,给定方法的名称
scheduledTimerWithTimeInterval:...
,您知道它将返回一个自动释放的对象(或者更准确地说,它将返回一个对象,该对象您不是所有者,并且您不必自己发送版本)如果不需要,您不必保留对创建的
NSTimer
的引用:计时器将被安排在RunLoop(即 RunLoop 会保留它直到使用它,并在使用完毕后释放它,因此您不必费心),因此它会自行存在。但是如果您不像第二个代码那样将返回的
NSTimer
存储在变量中,那么您将无法取消计时器(如果您想取消的话)。特别是,如果您设置了重复计时器,则需要将其存储在变量中,以便稍后可以访问它,特别是向其发送invalidate
消息,以便可以取消它。In either way, there is no memory leak. The second solution is just affecting the result to a variable, whereas the first one don't store the result, but the effect are the same.
As the naming convention suggests, given the name
scheduledTimerWithTimeInterval:...
of the method, you know that it will returns an autoreleased object (or to be more precise, it will return an object which you are not the owner, and for which you won't have to send a release to by yourself)You don't have to hold a reference to the created
NSTimer
if not needed: the timer will be scheduled on the RunLoop (and that's the RunLoop that will retain it until it is used, and release it when done, so you don't have to bother), so it will live by itself.But if you don't store the returned
NSTimer
in a variable like in your second code, you won't be able to cancel the timer if you ever wanted to. Especially, if you setup a repeating timer, you will need to store it in a variable so that you can access it later, especially to send it aninvalidate
message so it can be cancelled.