0

嗨,提前感谢。我有一个问题,当我NSTimer在一个视图中启动一个,然后用一个切换到另一个视图时UIPickerView,它UIPickerView的行为会受到影响。我在任何视图和包含 的视图之间来回切换NSTimer的次数越多, 的行为受到的影响就越大——它们滞后并且移动缓慢——最终达到不调用该方法UIPickerView的地步。受到影响的不仅仅是一个,而是我的应用程序中的所有内容。UIPickerViewDidSelectRowUIPickerViewUIPickerView

如果我决定不首先激活NSTimer,我的UIPickerViews工作没有问题。但是,当我调用这些NSTimer方法时,在包含 和任何其他视图的视图之间切换回来和第四NSTimer次可能六次之后,我的应用程序UIPickerView都完全停止工作。为了恢复它们的正确行为,我需要关闭应用程序并重新启动它。

我正在使用ARC,所以我没有NSTimer手动发布 - 但我认为这与我的问题有关。我猜NSTimer每次我切换回包含NSTimer. 无论如何,这是我编码任何东西的第二次努力,所以我不确定如何解决这个问题,尽管我已经读过NSTimerandUIPickerView可以通过相同的NSRunLoopor 线程分配,但我不确定这意味着什么。

无论如何,这是我的代码 - 它非常通用的样板代码。

-(void)showActivity:(NSTimer *)tim {

    NSDate *currentDate = [NSDate date];
    NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
    NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];

    NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"HH:mm:ss.S"];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
    NSString* timeString = [dateFormatter stringFromDate:timerDate];
    stopWatchLabel.text = timeString;

}


- (IBAction)onStartPressed:(UIButton *)sender; {

    stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1/10
                                                  target:self
                                                selector:@selector(showActivity:)
                                                userInfo:nil
                                                 repeats:YES];
    // Save the new start date every time
    startDate = [[NSDate alloc] init]; // equivalent to [[NSDate date] retain];
    NSDate *savedMentionDate = [[NSUserDefaults standardUserDefaults] objectForKey:@"mostRecentMentionDate"];

    if (savedMentionDate == nil) {
        //There is no existing mention, so save the most recent one
        [[NSUserDefaults standardUserDefaults]setObject:startDate forKey:@"mostRecentMentionDate"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    } else {
        startDate = savedMentionDate;
    }

    [stopWatchTimer fire];

    timerSetting = 0;

    NSNumber* timerSettingNS = [[NSNumber alloc] initWithInt:timerSetting];
    [[NSUserDefaults standardUserDefaults] setObject:timerSettingNS forKey:@"timerSetting"];
    [[NSUserDefaults standardUserDefaults] synchronize];

}


- (IBAction)onStopPressed:(UIButton *)sender {

    [stopWatchTimer invalidate];

}


- (IBAction)resetTimer:(UIButton *)sender; {

    stopWatchLabel.text = @"00:00:00.0";

    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObjectForKey:@"mostRecentMentionDate"];

    timerSetting = 1;

    NSNumber* timerSettingNS = [[NSNumber alloc] initWithInt:timerSetting];
    [[NSUserDefaults standardUserDefaults] setObject:timerSettingNS forKey:@"timerSetting"];
    [[NSUserDefaults standardUserDefaults] synchronize];

}

-(void)ViewDidLoad {
    ...
    ...
    NSNumber* timerSettings = [defaults objectForKey:@"timerSetting"];

    if (timerSettings == nil || timerSettings.intValue == 1) {

        [self resetTimer:resetTime];

    } else if (timerSettings.intValue == 0) {

        [self onStartPressed:start];

    }

}
4

2 回答 2

0

我想出了一个解决办法。我已在使应用程序切换视图的所有方法中插入了代码 [stopWatchTimer invalidate]。我很惊讶这项工作,因为当我在 viewDidLoad 和 viewDidUnload 方法中包含 [stopWatchTimer invalidate] 时,它没有任何效果......

于 2012-12-27T08:33:07.890 回答
0

我想出了一个解决办法。我已在使应用程序切换视图的所有方法中插入了代码 [stopWatchTimer invalidate]。

这或多或少是任何人会告诉你的,因为:

我很惊讶这项工作,因为当我在 viewDidLoad 和 viewDidUnload 方法中包含 [stopWatchTimer invalidate] 时,它没有任何效果......

这些方法只在非常特定的场合被调用:

viewDidLoad在加载视图控制器的视图时调用。(应该不会太意外……)

重要的部分是理解什么load意思:

当视图控制器被实例化时——无论是从 NIB 还是在代码中——它都没有视图。相反,它所拥有的是在被要求时如何为一个人服务的信息。

因此,当您将view消息发送到 UIViewController 时,它会判断它是否已经_view填充了其实例变量。如果不是,它将调用它自己的loadView方法,该方法将做任何必要的事情来用有意义的东西填充该实例变量。然后它会向自己发送viewDidLoad消息,以完成它管理的视图层次结构的设置,然后它才会返回_view.

这意味着viewDidLoad在视图控制器视图的整个生命周期中只调用一次。但是,这是什么意思?

在 iOS 5 和更早的版本中,视图的生命周期与它是可见视图层次结构的一部分相关联:当它不包含在一个视图中,并且其拥有的视图控制器收到内存警告时,基本实现基本上会查看视图是否有一个超级视图,并且(如果没有)它将调用viewWillUnload、释放和 nil out _view,并最终调用viewDidUnload以完成此过程。(这就是为什么在一些蹩脚的遗留代码库中,您可能会发现didReceiveMemoryWarning不调用的覆盖super...)

从 iOS 6 开始,UIViewController 不再这样做了!

这就是为什么不推荐使用 viewWillUnload 和 viewDidUnload 的原因:视图一直存在,直到其拥有的视图控制器被释放,因此不再调用这些方法。

有了这些,清除计时器的相关情况是什么?1.viewWillDisappear:你的观点即将“离开舞台”,所以拆除任何只有在它位于前面和中心时才相关的东西。2. 每当您要遮盖受计时器影响的部分时。这可能是因为您正在呈现另一个视图控制器,或者显示其他东西(如 UIPickerView),它们隐藏了它们下方的大部分屏幕。3. 每当您需要重新配置/重置计时器时。(未能做到这一点是您的应用程序一开始就戛然而止的原因。)

在 Xcode 中和在线提供了大量关于这些问题的优秀文档:

  • View Contoller Programming Guide绝对是 iOS 的必读之物。
  • NSTimer 类参考和链接的配套指南非常好。确保在“任务”部分之前阅读概念部分。在 NSTimer 标签下提出的任何问题(实际上与 NSTimer 相关)中超过 90% 的问题都不会被问到,如果人们真的阅读了这篇文章……</li>
于 2012-12-27T10:41:02.860 回答