NSTimer可能导致崩溃

时间:2012-02-24 15:54:54

标签: objective-c ios cocoa nstimer

使用NSTimer时遇到问题。 我们假设我有这种架构:

ThreadedClass.m(包含NSTimer *计时器;)

- (id) init {
  if (self = [super init]) {
    // do blablabla
    [self launchAThread];
  }
  return self;
}


- (void) launchAThread {
    [NSThread detachNewThreadSelector:@selector(selectorToMyThreadFunction)
                             toTarget:self
                           withObject:nil];
}


- (void) selectorToMyThreadFunction {
    //I do my stuff in here
    //Then i relaunch a Timer to call this function
    //periodically but it has to be "atomic" so no
    //repeating timer since i don't know the time
    //this function will take

    //I do some [self changeSomething];

    [self restartTimer];

    //MyThread ends here (and might be recreated by the Timer's bip
}

- (void)restartTimer {
    if (![NSThread isMainThread]) {
      [self performSelectorOnMainThread:@selector(restartTimer)
                             withObject:nil
                          waitUntilDone:NO];
      return;
    }

    [timer invalidate];
    [timer release];
    timer = [[NSTimer scheduledTimerWithTimeInterval:interval
                                              target:self
                                            selector:@selector(launchWithTimer:)
                                            userInfo:nil
                                             repeats:NO] retain];
}

- (void) launchWithTimer:(NSTimer *)theTimer {
  if (theTimer == timer)
  {
    [timer release];
    timer = nil;
    [self launchAThread];
  }
  else
  {
    //Nothing to be done in here, a user launch a thread manually
  }
}

所以让我们假设类的用户分配它并在之后立即释放它。我的计时器仍然存在并且对象也是(因为计时器有保留)。 当计时器将触发时,它将执行[self launchAThread],然后计时器将使自身无效并释放它将释放我的对象,该对象现在具有retainCount = 0 ...让我们假设,再一次,对象被解除分配之后,这将导致崩溃,我无能为力阻止它出现在我脑海中。

我同意,这是很多假设,但我很想知道是否有人已经有这个问题以及他是如何解决的。

感谢阅读,我希望我很清楚! :)

5 个答案:

答案 0 :(得分:1)

哟必须在释放之前始终使您的计时器无效。如果计时器是视图控制器的一部分,我总是在viewWillDisappear中使它失效。对我来说,奇怪的是NSTimers保留了他们的所有者。我认为最好的方法是创建 - (void)cleanUp方法,它将使计时器失效并警告类的用户在释放之前始终使用cleanUp。如果有人知道更好的方式,我会很高兴。

答案 1 :(得分:0)

只要你没有使用重复计时器,为什么不使用dispatch_after?您将省去NSTimer对象的头痛和开销。如果你坚持使用GCD,你也可以避免拨打detachNewThreadSelector:

答案 2 :(得分:0)

NSRunloop将为您保留计时器,这意味着您根本没有保留/释放它

答案 3 :(得分:0)

由于我正在创建一个库,我不能假设用户会随时调用cleanUp函数。

所以为了解决我的问题,我添加了一个新的“层”:一个新的类,它将执行线程和计时器部分,这样我就是这个类的用户,我知道我必须清理它!

答案 4 :(得分:0)

我首先使用了一种cleanUp类型的功能。 我还有一个对象A拥有对象B,它包含定时器 - 它保留对象B.当对象A被释放时,它会释放对象B,但是B仍然存在,因为计时器保留了它。然后在方法中触发了但是计时器,我正在使用委托关系来回调对象A→硬崩溃。这是对象A需要“清理”B的计时器的地方。如果其他对象也依赖于对象B,这可能会导致其他问题。而且A类不应该也可能不知道B类的实现秘密。:-PI猜测一个好的解决方案可能是取消设置该委托发布之前的关系是在A的dealloc中完成的,因为你不知道即使你释放它也不会死B - 别人可能会保留它(就像D *** NSTIMER一样)... :-P < / p>