暂停 NSTimer

发布于 2024-11-04 07:30:43 字数 1195 浏览 4 评论 0原文

我有一个 UIView ,其中有一个 UITableView 和一个 UIImageViewUITableView 占据了 UIView 的上半部分。 UIImageView 占据UIView 的下半部分。

我正在使用 NSTimer 来更新 UIImageView 中显示的图像。基本上,每 3 秒,UIImageView 就会加载一个新的 UIImage

问题是,如果我从 UITableView 中选择一行,NSTimer 就会继续运行。如何在 didSelectRowFromIndexPath 上停止 NSTimer,然后在视图返回屏幕时再次启动它?

-(void)viewDidLoad {
NSThread* timerThread = [[NSThread alloc] initWithTarget:self selector:@selector(startTimerThread) object:nil]; //Create a new thread
    [timerThread start]; //start the thread

} // end viewDidLoad

//
-(void) startTimerThread {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    [[NSTimer scheduledTimerWithTimeInterval: 3.0
                                      target: self
                                    selector: @selector(loadNextPhoto)
                                    userInfo: nil
                                     repeats: YES] retain];

    [runLoop run];
    [pool release];
}

I have a UIView with a UITableView and a UIImageView in it. The UITableView takes up the top half of the UIView. The UIImageView takes the bottom half of the UIView.

I am using an NSTimer to update the image that is being displayed in the UIImageView. Basically, every 3 seconds, the UIImageView loads in a new UIImage.

Problem is, if I select a row from the UITableView, the NSTimer keeps running. How can I stop the NSTimer on didSelectRowFromIndexPath, and then start it again when the view returns to the screen?

-(void)viewDidLoad {
NSThread* timerThread = [[NSThread alloc] initWithTarget:self selector:@selector(startTimerThread) object:nil]; //Create a new thread
    [timerThread start]; //start the thread

} // end viewDidLoad

//
-(void) startTimerThread {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    [[NSTimer scheduledTimerWithTimeInterval: 3.0
                                      target: self
                                    selector: @selector(loadNextPhoto)
                                    userInfo: nil
                                     repeats: YES] retain];

    [runLoop run];
    [pool release];
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

只等公子 2024-11-11 07:30:43

保留对您创建的计时器的引用,以便您可以在需要时停止它。下次您需要它时,您只需创建一个新计时器即可。听起来您执行此操作的最佳位置是 viewDidAppear: 和 viewWillDisappear: 。我不确定你为什么要在新线程上启动计时器。你可能有充分的理由这样做,但我从来不需要这样做。

//This code assumes you have created a retained property for loadNextPhotoTimer

    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        [self startTimer];
    }

    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        [self stopTimer];
    }

    - (void)startTimer {
        NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:3.0] interval:3.0 target:self selector:@selector(loadNextPhoto) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        self.loadNextPhotoTimer = timer;
        [timer release];
    }

    - (void)stopTimer {
        [self.loadNextPhotoTimer invalidate];
        self.loadNextPhotoTimer = nil;
    }

Keep a reference to the timer you create so you can stop it when needed. The next time you need it you can just create a new timer. It sounds like the best places for you to do this are in viewDidAppear: and viewWillDisappear:. I'm not sure why you are starting the timer on a new thread. You may have a good reasons for doing so but I have never needed to do this.

//This code assumes you have created a retained property for loadNextPhotoTimer

    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        [self startTimer];
    }

    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        [self stopTimer];
    }

    - (void)startTimer {
        NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:3.0] interval:3.0 target:self selector:@selector(loadNextPhoto) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        self.loadNextPhotoTimer = timer;
        [timer release];
    }

    - (void)stopTimer {
        [self.loadNextPhotoTimer invalidate];
        self.loadNextPhotoTimer = nil;
    }
余生一个溪 2024-11-11 07:30:43

您可以使用 NSTimer 的 invalidate 方法来销毁计时器。

然后,当您返回视图时,您必须重新创建它,就像在 startTimerThread 方法中所做的那样。

You can use the NSTimer's invalidate method to destroy the timer.

You'll then have to recreate it, as you did in your startTimerThread method, when you return to the view.

情场扛把子 2024-11-11 07:30:43

要从 startTimerThread 方法外部访问线程,您应该向您的类添加一个属性。我建议使用属性而不是 ivar,因为你可以自动合成原子访问器。您对计时器的操作取决于您是要暂停还是停止它。

停止计时器意味着下次启动计时器时,计时器将在还剩 3 秒时开始。这意味着如果计时器在您停止时会在 1 秒内触发,那么在您再次启动后仍需要 3 秒才能触发。然而,停止是非常简单的。 stopTimerThread 的定义如下:

- (void)stopTimerThread {
    NSTimer *theTimer = self.timer;
    [theTimer invalidate];
    self.timer = nil;
}

由于您的另一个线程中的 runloop 现在没有源,它会自动退出并且线程将结束,因此您可以在以下情况下使用 startTimerThread你想重新开始。

暂停定时器意味着,如果暂停时它会在 1 秒内触发,那么在您重新启动定时器后,它会在 1 秒内触发。为此,您还需要一个包含计时器触发前剩余时间的属性,该属性将在 stopTimerThread 中设置并在 startTimerThread 中使用。 stopTimerThread 的实现如下:

- (void)stopTimerThread {
    NSTimer *theTimer = self.timer;
    NSDate *fireDate = [theTimer fireDate];
    [theTimer invalidate];
    self.timerTimeRemaining = - [fireDate timeIntervalSinceNow];
    self.timer = nil;
}

请注意,剩余时间设置为时间间隔的负数,因为触发日期将在现在之前。您还必须修改 startTimerThread 以在设置计时器时考虑剩余时间。

- (void)startTimerThread {
    // set up autorelease pool, get run loop
    NSTimeInterval timeLeft = self.timerTimeRemaining;
    if(timeLeft <= 0.0) timeLeft = 3.0;
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:timeLeft];
    NSTimer *theTimer = [[NSTimer alloc] initWithFireDate:fireDate interval:3.0 target:self selector:@selector(loadNextPhoto) userInfo:nil repeats:YES];
    [runLoop addTimer:theTimer forMode:NSDefaultRunLoopMode];
    self.timer = theTimer;
    [theTimer release];
    [runLoop run];
    // clean up
}

To get access to the thread from outside the startTimerThread method, you should add a property to your class. I would suggest property over ivar because you can have atomic accessors synthesized automatically. What you do with the timer depends on whether you want to pause or stop it.

Stopping the timer means the next time you start it, it will start with the full 3 seconds remaining. This means if the timer will fire in 1 second when you stop it, it will still take 3 seconds to fire after you start it again. However, stopping is very simple. A stopTimerThread would be defined as follows:

- (void)stopTimerThread {
    NSTimer *theTimer = self.timer;
    [theTimer invalidate];
    self.timer = nil;
}

Since the runloop in your other thread now has no sources, it will automatically exit and the thread will end, so you can use startTimerThread when you want to start it again.

Pausing the timer means that, if it will fire in 1 second when you pause it, it will fire 1 second after you restart it. To do this, you will also need a property containing the time remaining before the timer fires, which will be set in stopTimerThread and used in startTimerThread. The implementation of stopTimerThread is as follows:

- (void)stopTimerThread {
    NSTimer *theTimer = self.timer;
    NSDate *fireDate = [theTimer fireDate];
    [theTimer invalidate];
    self.timerTimeRemaining = - [fireDate timeIntervalSinceNow];
    self.timer = nil;
}

Notice that the time remaining is set to be the negative of the time interval, since the fire date will be before now. You will also have to modify startTimerThread to take the time remaining into account when setting up the timer.

- (void)startTimerThread {
    // set up autorelease pool, get run loop
    NSTimeInterval timeLeft = self.timerTimeRemaining;
    if(timeLeft <= 0.0) timeLeft = 3.0;
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:timeLeft];
    NSTimer *theTimer = [[NSTimer alloc] initWithFireDate:fireDate interval:3.0 target:self selector:@selector(loadNextPhoto) userInfo:nil repeats:YES];
    [runLoop addTimer:theTimer forMode:NSDefaultRunLoopMode];
    self.timer = theTimer;
    [theTimer release];
    [runLoop run];
    // clean up
}
桃酥萝莉 2024-11-11 07:30:43

创建一个标志(BOOL)来控制图像的更新。

当您希望更新图像的例程忽略它是由计时器事件触发调用的事实时,请清除它。当您希望恢复图像更新时,只需设置该标志即可。也许是这样的:

-(void)ImageUpdater:(NSTimer *)theTimer
{
  if(image_updates_enabled)
  {
     // Code to update image
  }
}

由于您每三秒才触发一个方法,因此让计时器运行并不是什么大问题。

您可以做的另一件事是设置计时器,使其重复。完成此操作后,可以在代码中的其他位置做出重新启用计时器的决定,而不是自动做出。您甚至可以在回调函数中执行此操作,并且如果您愿意,仍然可以使用“image_updates_enabled”标志。

Create a flag (BOOL) to control the updating of the image.

Clear it when you want the routine that updates the image to ignore the fact that it was called by the timer event firing. When you want the image updates to resume, just set the flag. Maybe something like this:

-(void)ImageUpdater:(NSTimer *)theTimer
{
  if(image_updates_enabled)
  {
     // Code to update image
  }
}

Since you are firing a method only every three seconds it isn't a big deal to just let the timer run.

The other thing you can to is to setup the timer so that it does not repeat. With that in place the decision to re-enable the timer could be made somewhere else in your code rather than automatically. You could even do it within the callback function and still use the "image_updates_enabled" flag if you wish.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文