【问题标题】:NSTimer crashing after app returns to foreground应用程序返回前台后 NSTimer 崩溃
【发布时间】:2013-07-10 01:32:51
【问题描述】:

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

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

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

@property (nonatomic, weak) NSTimer *updateDateTimer;

这是将项目放入我的表格视图的代码:

- (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];

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

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

【问题讨论】:

  • 什么时候取消控制器的观察者身份?
  • @Wain 你是说这个吗? [[NSNotificationCenter defaultCenter] removeObserver:self];?如果是这样,我已将此代码放在dealloc
  • 好,在上面打个断点,看看什么时候命中。
  • @Wain dealloc 在我选择一个不是我当前的 VC 的菜单项(加载另一个视图控制器)后立即被调用。
  • 您已经在getAllItems 上放置了一个断点,以查看它在您的崩溃场景中是如何调用的?

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


【解决方案1】:

你应该是invalidating your timers when your app becomes inactive-applicationWillResignActive: 是这样做的好地方。当应用再次激活时,您可以创建新的计时器。

有根据的猜测是,您的应用程序正在崩溃,因为当应用程序处于非活动状态时计时器会自动终止,然后当您的应用程序返回前台并尝试访问不再有效的计时器时您会崩溃。

【讨论】:

  • 就是这样,我为UIApplicationWillResignActiveNotification 添加了一个NSNotification 并通过在计时器退出活动之前终止计时器来处理它。当它回来时,我在viewWillAppear 中重新创建计时器。谢谢!
【解决方案2】:

一旦你在计时器上调用 invalidate,你就不能再次使用它 - How to "validate" a NSTimer after invalidating it?

如果我想要一个可以随意“打开/关闭”的计时器,我会使用BOOL useTimer 或其他决定计时器是否应该触发的东西,用于重复计时器。

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

【讨论】:

    猜你喜欢
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    相关资源
    最近更新 更多