Ios 目标c:使用NSTimer对象进行内存管理

Ios 目标c:使用NSTimer对象进行内存管理,ios,objective-c,automatic-ref-counting,nstimer,release,Ios,Objective C,Automatic Ref Counting,Nstimer,Release,在该方法的末尾,我预计会丢失引用t,因此,对于ARC,会自动调用release并释放NSTimer对象,相反,它似乎仍在内存中(exec_方法每2秒重复执行一次)…或者当系统需要内存空间时,它将被释放?您确实正确地理解了ARC-这只是一个稍微不明显的情况,因为有一个额外的强引用指向您的对象,您无法看到NSTimer的行为与预期不符,因为它被安排在运行循环中,这意味着它也被保留在运行循环中。因此,当你的局部记忆消失时,对象仍保留在内存中 ARC底层使用一个参考计数系统-每个对象都有一个分配给它的数

在该方法的末尾,我预计会丢失引用t,因此,对于ARC,会自动调用release并释放NSTimer对象,相反,它似乎仍在内存中(exec_方法每2秒重复执行一次)…或者当系统需要内存空间时,它将被释放?

您确实正确地理解了ARC-这只是一个稍微不明显的情况,因为有一个额外的强引用指向您的对象,您无法看到
NSTimer
的行为与预期不符,因为它被安排在运行循环中,这意味着它也被保留在运行循环中。因此,当你的局部记忆消失时,对象仍保留在内存中

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


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

您确实正确地理解了ARC-这只是一个稍微不明显的情况,因为您无法看到对对象的附加强引用
NSTimer
的行为与预期不符,因为它被安排在运行循环中,这意味着它也被保留在运行循环中。因此,当你的局部记忆消失时,对象仍保留在内存中

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

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

来自Apple文档:

计时器与运行循环一起工作。为了有效地使用计时器, 您应该知道运行循环是如何运行的请参见nsrunlop和 线程编程指南。请特别注意运行循环 保持对他们计时器的强引用,所以你不必这样做 在添加计时器后,维护自己对计时器的强引用 到运行循环

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

为了简化这个过程,您可以创建两个方法,一个用于创建并启动计时器,另一个用于使时间无效。这些方法要求您将时间声明为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,并且应该尽可能安全地结束它。

来自Apple docs:

计时器与运行循环一起工作。为了有效地使用计时器, 您应该知道运行循环是如何运行的请参见nsrunlop和 线程编程指南。请特别注意运行循环 保持对他们计时器的强引用,所以你不必这样做 在添加计时器后,维护自己对计时器的强引用 到运行循环

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

为了简化这个过程,您可以创建两个方法,一个用于创建并启动计时器,另一个用于使时间无效。这些方法要求您将时间声明为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,并且应该尽可能安全地结束它