我正在createTimer
方法中创建一个NSTimer,我想在后面的cancelTimer
方法中引用它。为方便起见,我通过保留的财产取得了NSTimer的所有权,以便我稍后再回头查看。令我困惑的问题是,如果我启动计时器,取消它并再次启动它,代码崩溃。
@property(nonatomic, retain) NSTimer *walkTimer;
-(void)createTimer {
NSTimer *tempTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTimerDisplay) userInfo:nil repeats:YES];
[self setWalkTimer:tempTimer];
}
-(void)cancelTimer {
[walkTimer release];
[[self walkTimer] invalidate];
}
现在我似乎通过将cancelTimer更改为:
来解决此问题-(void)cancelTimer {
[self setWalkTimer:nil];
[[self walkTimer] invalidate];
}
我很好奇为什么发布不起作用,我的理解是:
修改
// this fails ...
-(void)cancelTimer {
[[self walkTimer] invalidate];
[walkTimer release];
}
// this works fine ...
-(void)cancelTimer {
[[self walkTimer] invalidate];
[self setWalkTimer: nil];
}
编辑:002
最初我认为我在混淆
@property(nonatomic, retain) NSTimer *walkTimer;
// &
[self setWalkTimer];
并且认为我需要一个版本来平衡属性,我不是用新集合覆盖它(要么是另一个对象或nil),最后在dealloc中释放属性。
属性(保留)是否与保留相同,我会说不,我认为这是我出错的地方。
编辑:003
关于这个问题,我认为我个人使用[walkTimer release]
错误地将事情搞糊涂了。结果,这个话题基本上浮现了一个我写成this的新问题
答案 0 :(得分:4)
在致电release
之前,您invalidate
。这意味着当您致电invalidate
时,您已经放弃了计时器的所有权。实际上,您最终会在解除分配的计时器实例上调用invalidate
。
在拨打invalidate
之前,您应该拨打release
。由于您使用的是保留属性,因此您只需将属性设置为nil
:
// Schedule the timer.
self.walkTimer = [NSTimer scheduledTimerWith...];
// Cancel the timer.
[self.walkTimer invalidate];
self.walkTimer = nil;
重要的是要记住Objective-C的Memory Management Rules - 如果您在其上调用alloc
,copy
或retain
,并且如果您拥有一个对象,你必须最终调用release
。在这种情况下,setWalkTimer:
会保留计时器,因为该属性声明为retain
- 这意味着您拥有计时器,并且必须在路上呼叫release
。 invalidate
方法不计算为放弃计时器的所有权。
当您计划一个计时器时,运行循环会保留它,当计时器触发或无效时,运行循环将释放它。但实际上,您不需要知道 - 这是一个实现细节。 release
之前invalidate
的调用仅用于在运行循环计划定时器时平衡retain
。
答案 1 :(得分:0)
您需要在发布前失效。计时器启动后,您是唯一一个在计时器上保留计时器的人。因此,当您调用release时,计时器将取消分配。然后,您在无效内存上调用invalidate,然后崩溃。
答案 2 :(得分:0)
self
设置为重复计时器的目标,除非您完全确定知道所有后果(...否则运行时会在泄露的计时器,目标和userInfos中淹死一只小猫 - 或者说是这样。)
请阅读并重新阅读NSTimer Class Reference中的“概述”,并特别注意最后一段。
简而言之:
NSTimer
个实例无法重复使用:
“一旦失效,计时器对象就无法重复使用”。因此,首先保留预定的计时器是没有意义的。
如果你需要坚持下去(例如为了取消它),请使用非拥有(又称弱)引用。
<强>更新强>
有关详细说明,请参阅my answer to your other question(它现在有图表 - 虽然只是链接 - 以及其他内容)。
请将此帖的其余部分(以及我的许多评论)视为过时。
您的财产变为
@property (nonatomic, assign) NSTimer *walkTimer;
顺便说一句:
-(void)cancelTimer {
[self setWalkTimer:nil]; // great, now [self walkTimer] returns nil so
[[self walkTimer] invalidate]; // here, you are calling [nil invalidate]
}
由于在目标C中消息nil绝对正常,你的崩溃奇迹般地消失了...而你的计时器将很快继续发射。
修改强>
我忘了提及:
一个计时器想要一个带有一个参数的选择器,这个参数将被触发...或者这只是一个错字?