目标 c:使用 NSTimer 对象进行内存管理
Posted
技术标签:
【中文标题】目标 c:使用 NSTimer 对象进行内存管理【英文标题】:objective c: memory management with NSTimer objects 【发布时间】:2015-08-30 14:27:35 【问题描述】:我是 Objective C 编程的新手,我来自 C++,并且会更好地了解 ARC 内存管理;如果我有以下情况:
-(void) test_method
NSTimer* t=[NSTimer ScheduledTimerWithTimeInterval:2
target:self selector;@selector(exec_method) userinfo:nil repeats:YES];
在方法结束时,我预计会丢失引用 t,因此,对于 ARC,自动调用 release 并释放 NSTimer 对象,相反,它似乎仍在内存中(exec_method 重复它每 2 秒执行一次)..或者当系统需要内存空间时它会被释放?
【问题讨论】:
【参考方案1】:您确实正确理解了 ARC - 这只是一个不太明显的情况,因为您看不到对您的对象的额外强引用。 NSTimer
的行为不符合预期,因为它被安排在运行循环上,这意味着它也被保留在那里。因此,当您的本地人离开时,该对象仍保留在内存中。
ARC 底层使用引用计数系统 - 每个对象都有一个分配给它的数字(称为保留计数),并且只有当该数字达到零时才会释放对象。当使用alloc
、copy
或new
创建对象时,保留计数设置为 1。当对象被另一个对象保留时,数目增加,当它被释放时减少(在 pre- ARC MRR 系统这些是程序员进行的实际方法调用 - retain
和 release
)。 ARC 以相同的方式工作,但只是在编译时自动添加相同的调用)。
因此,在这种情况下,ARC 生成的对 release
的隐式调用只是将计数从 2 减少 1,但由于它没有达到零,因此不会释放对象。使计时器无效会将其从运行循环中移除,并导致其被释放。
【讨论】:
【参考方案2】:来自 Apple 文档:
定时器与运行循环一起工作。为了有效地使用计时器, 你应该知道运行循环是如何运作的——参见 NSRunLoop 和 线程编程指南。特别注意运行循环 保持对他们的计时器的强烈引用,所以你不必 添加计时器后,保持您自己对计时器的强引用 到一个运行循环。
您必须使 NSTimer 无效才能将其从运行循环中移除。
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/
为了简化这个过程,你可以做的是创建两种方法,一种是创建和启动计时器,另一种是使时间无效。这些方法需要您将时间声明为 IVAR。
斯威夫特:
let timer = NSTimer(timeInterval: 1.0, target: self, selector: "incrementCompletedUnitCount:",
userInfo: nil, repeats: true)
progress.cancellationHandler =
timer.invalidate()
progress.cancel()
目标-C
NSTimer * _studentTimer1;
-(void)startStudentTimer
NSLog(@"***TIMER STARTED***");
_studentTimer1 = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(dowork) userInfo:nil repeats:TRUE];
-(void)invalidateStudentTimer1
[_studentTimer1 invalidate];
另外,为了安全起见,您可能希望将您的失效方法放在视图控制器的 dealloc 方法中。
您还可以考虑通过使用指向计时器的弱指针来采取额外的安全措施,如下所示:
NSTimer* __weak timer = [NSTimer scheduledTimerWithTimeInterval:30.0f target: self selector:@selector(tick) userInfo:nil repeats:YES];
或作为 IVAR:
NSTimer * __weak _studentTimer1;
不,至于你的最后一个问题,时间会一直停留在运行循环中,直到你明确地将其无效,这就是为什么你需要小心使用 NSTimer 并且应该尽可能安全地将其包装起来。
【讨论】:
以上是关于目标 c:使用 NSTimer 对象进行内存管理的主要内容,如果未能解决你的问题,请参考以下文章