objective c: 使用 NSTimer 对象进行内存管理

objective c: memory management with NSTimer objects

我是 Objective C 编程新手,我来自 C++,更了解 ARC 内存管理;如果我有以下情况:

-(void) test_method
{
 NSTimer* t=[NSTimer ScheduledTimerWithTimeInterval:2
 target:self  selector;@selector(exec_method) userinfo:nil repeats:YES];
}

在方法结束时,我预计会丢失引用 t,因此,对于 ARC,自动调用释放并释放 NSTimer 对象,相反它似乎仍在内存中( exec_method 每 2 秒重复一次执行)..或者当系统需要 space 内存时它会被释放?

您确实正确理解了 ARC - 这只是一个稍微不明显的案例,因为有一个您看不到的对您的对象的额外强引用。 NSTimer 没有按预期运行,因为它被安排在 运行 循环上这一事实意味着它也保留在那里。因此,当您的本地消失时,该对象仍保留在内存中。

ARC 底层使用引用计数系统 - 每个对象都有一个分配给它的数字(称为保留计数),只有当该数字达到零时才会释放该对象。当使用 alloccopynew 创建对象时,保留计数设置为 1。当对象被另一个对象保留时,数量会增加,而当它被释放时,它会增加减少(在 ARC 之前的 MRR 系统下,这些是程序员进行的实际方法调用 - retainrelease)。 ARC 以相同的方式工作,但只是在编译时自动添加相同的调用)。

所以在这种情况下,ARC 生成的对 release 的隐式调用只是将计数从 2 减 1,但由于它没有达到零,因此对象没有被释放。使计时器无效会将其从 运行 循环中移除,并导致其被释放。

来自 Apple 文档:

Timers work in conjunction with run loops. To use a timer effectively, you should be aware of how run loops operate—see NSRunLoop and Threading Programming Guide. Note in particular that run loops maintain strong references to their timers, so you don’t have to maintain your own strong reference to a timer after you have added it to a run loop.

您必须使 NSTimer 无效才能将其从 运行 循环中删除。

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/

为了简化这个过程,你可以做的是创建两个方法,一个创建和启动定时器,一个使时间无效。这些方法需要您将时间声明为 IVARs。

Swift:

let timer = NSTimer(timeInterval: 1.0, target: self, selector: "incrementCompletedUnitCount:",
    userInfo: nil, repeats: true)

progress.cancellationHandler = {
    timer.invalidate()
}

progress.cancel()

Objective-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 并且应该尽可能安全地包装它尽可能。