当我调用 [Timer isValid] 或 [Timer invalidate] 时,NSTimer 崩溃
Posted
技术标签:
【中文标题】当我调用 [Timer isValid] 或 [Timer invalidate] 时,NSTimer 崩溃【英文标题】:NSTimer crashes, when I call [Timer isValid] or [Timer invalidate] 【发布时间】:2011-04-11 04:17:19 【问题描述】:我的 iPhone 应用中有两个 NSTimer。 DecreaseTimer 工作正常,但是当我调用 [timerCountSeconds isValid] 或 [timerCountSeconds invalidate] 时 TimerCountSeconds 崩溃。它们是这样使用的:
-(id)initialize //Gets called, when the app launches and when a UIButton is pressed
if ([timerCountSeconds isValid])
[timerCountSeconds invalidate];
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event //Gets called, when you begin touching the screen
//....
if ([decreaseTimer isValid])
[decreaseTimer invalidate];
timerCountSeconds = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
//....
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event //Gets called, when you stop touching the screen(not if you press the UIButton for -(id)initialize)
//...
decreaseTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(decrease) userInfo:nil repeats:YES];
//...
-(void)comept3 //Gets calles when you rubbed the screen a bit
if ([timerCountSeconds isValid])
[timerCountSeconds invalidate];
我做错了什么? 你能帮帮我吗?
【问题讨论】:
你初始化TimerCountSeconds和DecreaseTimer了吗? 我在头文件中声明了它们...我在“touchesEnded”和“touchesBegan”方法中初始化了它们 显示更多代码。此外,使用像DecreaseTimer
这样的名称作为实例变量通常是一个非常糟糕的主意。以大写字母开头的名称用于类和结构。考虑使用 Apple 提倡的一致风格。
好的,我改了变量名...我忘了输入“comept3”方法...这可能会帮助你帮助我;)
【参考方案1】:
您应该在invalidate
之后将NSTimer
对象设置为nil
,因为invalidate
方法调用也执行release
(根据Apple 文档)。如果您不这样做,则在其上调用诸如 isValid
之类的方法可能会导致您的崩溃。
【讨论】:
双重投票 - 为这个问题搜索了几个小时......顺便说一句:如果在其他地方使用 isValid 检查它,保留 NSTimer 可能是非常明智的。如果不保留,它可能会在触发时自动释放(另见 Chuck 的回答)。【参考方案2】:很可能存储在该变量中的计时器已被释放。如果你想保留它任意长的时间,你需要保留它。
【讨论】:
什么时候解除分配?那我什么时候必须保留它? 当 runloop 决定它可以被释放时,它将被释放。如果你想保留它,你应该在将它存储在某个地方时保留它,就像任何其他对象一样。 好吧,我想我明白了;)我在初始化后保留了它……现在它不再崩溃了:)对吗?【参考方案3】: [objTimer retain];
那么它不会在任何时候崩溃。在初始化计时器后使用它,这样它就可以正常工作了......
【讨论】:
【参考方案4】:您需要在主线程中设置计时器。 NSTimer 不会在后台线程中触发。
对象:
dispatch_async(dispatch_get_main_queue(), ^
_timer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(YOUR_METHOD) userInfo:nil repeats:YES];
);
斯威夫特:
dispatch_async(dispatch_get_main_queue())
timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: "YOUR_METHOD", userInfo: nil, repeats: true)
【讨论】:
invalidate() 怎么样。我还需要在主线程中调用它吗?【参考方案5】:您需要在初始化时实际初始化TimerCountSeconds
和DecreaseTimer
成员。假设您的控制流程是:
...
myObject = [[MyObject alloc] initialize];
...
[myObject touchesBegan:...]
...
[myObject touchesEnded:...]
...
那么当你调用initialize
时TimerCountSeconds
还没有被初始化,所以你在逻辑上这样做
[<random pointer> isValid]
这会崩溃。同样,第一次调用 touchesBegan 时,DecreaseTimer 无效。
在您的初始化方法中,您需要在尝试使用任何内容之前实际初始化所有内容。
您似乎也在泄漏计时器(touchesBegin
使计时器无效但不释放它)
【讨论】:
如果这些是实例变量,它们就不是“随机指针”——它们是 nil。【参考方案6】:-(void)StopScanTimer
if(scanTimer != nil)
[scanTimer invalidate];
scanTimer = nil;
-(void)StartScanTimer
[self StopScanTimer];
float duration = 10.0f;
scanTimer = [NSTimer timerWithTimeInterval:duration target:self selector:@selector(OnScanTimerElapsed) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:scanTimer forMode:NSRunLoopCommonModes];
[scanTimer retain];
-(void) OnScanTimerElapsed
// Do something
如果你删除“[scanTimer retain];”,当你调用invalidate时它会崩溃。 如果您想重新使用它,请始终保留计时器。
【讨论】:
以上是关于当我调用 [Timer isValid] 或 [Timer invalidate] 时,NSTimer 崩溃的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET 4.5 自定义验证属性。 IsValid() 调用太晚了
[转]验证发生前无法调用 Page.IsValid。应在 CausesValidation=True 且已启动回发的控件
Springboot+JPA(Hibernate)+Oracle AbstractMethodError 未定义或继承 isValid(int) 的实现