7

I have a UIScrollView that has a series of labels which are rapidly updating numbers (every .06 seconds). While the scroll view is moving, however, the NSTimer is paused and does not continue until after the scrolling and the elastic animation have finished.

How can I avoid this and have the NSTimer run regardless of the state of the scroll view?

Peter Kazazes
  • 3,600
  • 7
  • 31
  • 60

3 Answers3

25

An easy way to fix this is adding your NSTimer to the mainRunLoop.

[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

To remove a timer from all run loop modes on which it is installed, send an invalidate message to the timer.

Iñigo Beitia
  • 6,303
  • 4
  • 40
  • 46
  • So with this I don't actually have to fire the timer, it's initiated when that line is executed, correct? – Peter Kazazes Aug 14 '11 at 20:25
  • From the documentation: "You can add a timer to multiple input modes. While running in the designated mode, the receiver causes the timer to fire on or after its scheduled fire date. Upon firing, the timer invokes its associated handler routine, which is a selector on a designated object." – Iñigo Beitia Aug 14 '11 at 20:28
1

for swift:

NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
Matt Wyeth
  • 1,124
  • 2
  • 10
  • 19
0

(Swift) An alternative: You can use a GCD-based timer system like this one:

class GCDTimer {

    private var _timer : dispatch_source_t?

    init() {

    }

    private func _createTheTimer(interval : Double, queue : dispatch_queue_t, block : (() -> Void)) -> dispatch_source_t
    {
        let timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        if (timer != nil)
        {
            dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, Int64(interval * Double(NSEC_PER_SEC))), UInt64(interval * Double(NSEC_PER_SEC)), (1 * NSEC_PER_SEC) / 10);
            dispatch_source_set_event_handler(timer, block);
            dispatch_resume(timer);
        }
        return timer;
    }


    func start(interval : Double, block : (() -> Void))
    {
        let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        _timer = _createTheTimer(interval, queue: queue, block: block)

    }

    func stop()
    {
        if (_timer != nil) {
            dispatch_source_cancel(_timer!);
            _timer = nil;
        }
    }
}
raf
  • 2,569
  • 20
  • 19
  • Here's how you would use it: `var myInterval:GCDTimer = GCDTimer() myInterval.start(1.0) { println("lol") }` – Thyselius Apr 18 '15 at 20:02
  • If you want to make an update to a UI element using this timer, you must do this on the main thread, like this: `dispatch_async(dispatch_get_main_queue(), { self.myUIImageView.image = UIImage(data: data as! NSData)! })` – Thyselius Apr 18 '15 at 20:43
  • glad you found it useful! – raf Apr 24 '15 at 14:56