You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

咨询从MFMailComposeViewController恢复时处理错误及答题游戏NSTimer异常问题

解决你的答题游戏两个核心问题

嘿,我来帮你搞定这两个iOS开发里的常见坑~

一、来电时计时器偷偷继续计时的问题

你现在用NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(decrementSpin) userInfo:nil repeats:YES]创建的计时器,在app被来电打断进入后台时,默认情况下系统其实会暂停RunLoop里的计时器,但可能你的场景下因为某些原因它还在跑?不管怎样,咱们主动控制它的生命周期就好:

具体实现步骤:

  1. 先在viewDidLoad里注册app前后台的通知监听:
- (void)viewDidLoad {
    [super viewDidLoad];
    // 监听后台/前台切换通知
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(appDidEnterBackground:) 
                                                 name:UIApplicationDidEnterBackgroundNotification 
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(appWillEnterForeground:) 
                                                 name:UIApplicationWillEnterForegroundNotification 
                                               object:nil];
}
  1. 实现通知处理方法,控制计时器的销毁和重建:
- (void)appDidEnterBackground:(NSNotification *)notification {
    // 进入后台时,先销毁计时器,同时记录当前剩余时间(假设你有个remainingTime变量存剩余时长)
    if (m_timer) {
        [m_timer invalidate];
        m_timer = nil;
        // 这里根据你的decrementSpin逻辑,把当前剩余时间存下来,比如:
        // self.remainingTime = 当前剩余的秒数;
    }
}

- (void)appWillEnterForeground:(NSNotification *)notification {
    // 回到前台时,重新启动计时器,从之前记录的剩余时间开始继续
    if (!m_timer) {
        m_timer = [NSTimer scheduledTimerWithTimeInterval:1.0f 
                                                   target:self 
                                                 selector:@selector(decrementSpin) 
                                                 userInfo:nil 
                                                  repeats:YES];
        // 同时更新界面上的时间显示,确保用户看到的是正确的剩余时长
    }
}
  1. 别忘了在dealloc里清理通知和计时器:
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    if (m_timer) {
        [m_timer invalidate];
        m_timer = nil;
    }
}

这样不管是来电还是切到其他app,计时器都会乖乖暂停,回来后继续正常计时~

二、从MFMailComposeViewController返回时的处理错误

这个问题本质上和上面的后台切换是一样的——打开邮件界面时app会进入后台状态,返回时需要手动恢复游戏状态。除了上面的通知监听,咱们还要配合邮件控制器的代理方法来处理:

具体操作:

  1. 确保你的ViewController遵守MFMailComposeViewControllerDelegate协议
  2. 实现代理方法,在关闭邮件后主动恢复计时器和游戏状态:
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
    [self dismissViewControllerAnimated:YES completion:^{
        // 邮件界面关闭后,检查计时器是否需要重启
        if (!m_timer) {
            m_timer = [NSTimer scheduledTimerWithTimeInterval:1.0f 
                                                       target:self 
                                                     selector:@selector(decrementSpin) 
                                                     userInfo:nil 
                                                      repeats:YES];
        }
        // 这里还可以恢复答题界面的交互、更新剩余时间显示等,确保游戏状态完全回到之前的样子
    }];
}

另外,还要检查你的decrementSpin方法逻辑,确保在恢复计时器时,剩余时间的计算是基于之前记录的值,而不是从头开始,这样用户回来后不会发现时间跳变。

总结一下,核心就是主动管理计时器的生命周期+维护好游戏状态变量,这样就能完美解决这两个问题啦~

内容的提问来源于stack exchange,提问作者odysseasg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:45:44