检查 NSTimer 是否有效时崩溃?

Crash when checking if NSTimer isValid?

我在控制台中收到此异常:

Error:

2015-06-25 23:12:01.841 Copyfeed for Mac[9512:584232] -[_NSViewLayoutAux invalidate]: unrecognized selector sent to instance 0x6000001657c0

检查我的计时器是否 valid/and 使它们无效时。

if ([_staticTimer isValid]) {
    [_staticTimer invalidate];
    _selectionTimer = 
            [NSTimer scheduledTimerWithTimeInterval:2 target:self 
            selector:@selector(hideHUD) userInfo:nil repeats:NO];
}

if ([_selectionTimer isValid]) {
    [_selectionTimer invalidate];
    _selectionTimer = 
           [NSTimer scheduledTimerWithTimeInterval:2 target:self 
           selector:@selector(hideHUD) userInfo:nil repeats:NO];
}

这是我的新代码:

 if (_selectionTimer != nil) {
        [_selectionTimer invalidate];
        _selectionTimer = nil;
        _selectionTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(hideHUD) userInfo:nil repeats:NO];
    }
    
    if (_staticTimer != nil) {
        [_staticTimer invalidate];
        _staticTimer = nil;
        _selectionTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(hideHUD) userInfo:nil repeats:NO];
    }


@property  (strong )NSTimer *staticTimer;
    @property  (strong )NSTimer *selectionTimer;

现在当我调试僵尸对象时出现这个错误。

2015-06-26 00:39:45.523 Copyfeed for Mac[11191:824502] *** -[CFRunLoopTimer release]: message sent to deallocated instance 0x608000175e40

使其无效后,应将 NSTimer 对象设置为 nilinvalidate 方法也执行 release。 如果您不这样做,在其上调用方法 isValid 可能会导致崩溃。

if (_selectionTimer != nil) {
    [_selectionTimer invalidate];
    _selectionTimer = nil;
    // do something
}

点击这里

if (_staticTimer != nil) {
        [_staticTimer invalidate];
        _staticTimer = nil;
        //_selectionTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(hideHUD) userInfo:nil repeats:NO];
        _staticTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(hideHUD) userInfo:nil repeats:NO];
    }

来自文档:

Because the run loop maintains the timer, from the perspective of memory management there's typically no need to keep a reference to a timer after you’ve scheduled it. Since the timer is passed as an argument when you specify its method as a selector, you can invalidate a repeating timer when appropriate within that method. In many situations, however, you also want the option of invalidating the timer—perhaps even before it starts. In this case, you do need to keep a reference to the timer, so that you can send it an invalidate message whenever appropriate. If you create an unscheduled timer (see “Unscheduled Timers”), then you must maintain a strong reference to the timer (in a reference-counted environment, you retain it) so that it is not deallocated before you use it.

所以你应该让计时器变弱而不是变强

这里有几个潜在的问题。

if (_staticTimer != nil) {
    [_staticTimer invalidate];
    _staticTimer = nil;
    _selectionTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(hideHUD) userInfo:nil repeats:NO];
}

您在这里所做的是覆盖 selectionTimer,即使它可能仍包含一个仍在 运行 循环中安排的计时器。所以如果你在这里重置属性,你也应该确保在这样做之前调用[_selectionTimer invalidate]

根据计时器启动时您在做什么,这可以解释 CFRunLoopTimer 上的崩溃。

在使用 NSTimer 时证明对我非常有帮助的一般性建议:我建议将所有包含预定计时器的属性声明为 weak,因为它们由运行 循环。这样,您不需要在使它们无效后将它们显式设置为 nil,而是每次您想要摆脱它时只需调用 invalidate,它也会自动变为 [=16] =] 一旦它被 运行 循环触发,释放它可能持有的所有数据。 请注意,这仍然需要您调用 invalidate 以防您想要取消计时器或在更换计时器之前调用,但在这样做之后您不再需要将其设置为 nil