应用程序返回前台后NSTimer崩溃

时间:2013-07-11 16:51:05

标签: ios objective-c crash nstimer memory-management

这个错误已经在我的代码中存在了好几天 - 我一直试图解决它,但无济于事。我已经在模拟器和设备上进行了大量的调试,日志记录,Crashlytics抛出崩溃日志,这与我的NSTimer在重新分配后发送消息有关。我会进一步解释。

NSTimer控制某些视图控制器上的UIToolbar标签,并不断更新标签以显示用户刷新UITableView时的相对时间。加载后,每次刷新时都会显示Updated just now,然后如果用户没有刷新/转到另一个VC,它会每60秒更新一次。所以,过了一会儿,它会显示Updated 1 minute agoNSTimer会触发执行UILabel更新的方法。在用户刷新时(通过拉动刷新控件),在我的getAllItems内手动调用此方法(这就是我传递nil的原因)。

我的NSTimer在我的超类中被定义为:

@property (nonatomic, weak) NSTimer *updateDateTimer;

这是将项目放入我的tableview的代码:

- (void)getAllItems
{
    KILL_TIMER(self.updateDateTimer);
    self.updateLabel = [Formatters boldLabelWithLabel:self.updateLabel
                                             withText:@"Checking for items..."
                                             withFont:[UIFont fontWithName:kOpenSansBold size:15.0f]];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self fetchObjectsWithRequest:self.request];
        sleep(1);
        dispatch_async(dispatch_get_main_queue(), ^{
                [self.refreshControl performSelector:@selector(endRefreshing) withObject:nil afterDelay:0];

            self.updatedDate = [NSDate date];
            [self updateTimer:nil];
            self.updateDateTimer = [NSTimer scheduledTimerWithTimeInterval:kToolbarUpdateLabelInterval
                                                                    target:self
                                                                  selector:@selector(updateTimer:)
                                                                  userInfo:nil repeats:YES];
        });
    });
}

KILL_TIMER(q)在我的超类中被定义为:

#define KILL_TIMER(q) if (q) {DDLogVerbose(@"KILLING TIMER: %@", q); [q invalidate]; q=nil;}

此定义以2种方式调用:

a)在我的getAllItems方法中:所以当我(重新)加载项目时(通过在viewDidLoad中调用该方法或者通过用户刷新表视图),我总是试图杀死当前的计时器这是活动的,显示'检查项目',获取项目,显示'刚刚更新',然后安排计时器每60秒执行一次。

b)在每个viewWillDisappear`上,如下:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    KILL_TIMER(self.updateDateTimer);
}

但是,如果我点击主页按钮,然后重新打开应用程序,它通常(并非总是,仅当我切换了视图控制器时)崩溃并显示以下消息(启用了NSZombies):

2013-07-11 17:21:37.576 App[3923:907] *** -[ItemCDTVC setUpdateDateTimer:]: message sent to deallocated instance 0x20bc49f0

我有一个NSNotification来调用我的getAllItems

// Notification received when user returns to app (refreshes the table view)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getAllItems) name:UIApplicationWillEnterForegroundNotification object:nil];

这只发生在我使用菜单切换视图控制器,离开应用程序并重新打开(应用程序未终止)之后。 如果用户停留在应用中,它不会崩溃,无论他们切换多少个视图控制器。

这是一个非常烦人的错误,因为虽然它很容易重现,但我不知道如何修复它。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:4)

你应该是invalidating your timers when your app becomes inactive-applicationWillResignActive:是一个很好的地方。您可以在应用再次变为活动状态时创建新的计时器。

一个有根据的猜测是你的应用程序崩溃了,因为定时器在应用程序变为非活动状态时自动被杀死,然后当你的应用程序返回到前台并尝试访问不再有效的计时器时崩溃。

答案 1 :(得分:2)

在计时器上调用invalidate后,您无法再次使用它 - How to "validate" a NSTimer after invalidating it?

如果我想拥有一个可以随意“打开/关闭”的计时器,我会使用BOOL useTimer或类似的东西决定计时器是否应该开启,重复计时器。

对于非重复计时器,我创建一个新计时器。