(Swift) Nstimer Stop When Scrolling

(Swift) NSTimer Stop when Scrolling

I created a simple project with a scrollView and a label that is updated with an NSTimer. When creating the timer with scheduledTimerWithInterval, the timer does not run when scrolling.

The solution is to create the timer with NSTimer:timeInterval:target:selector:userInfo:repeats and then call addTimer on NSRunLoop.mainRunLoop() with mode NSRunLoopCommonModes. This allows the timer to update while scrolling.

Here it is running:

Demo .gif

Here is my demo code:

class ViewController: UIViewController {

@IBOutlet weak var timerLabel: UILabel!
var count = 0

override func viewDidLoad() {
super.viewDidLoad()

timerLabel.text = "0"

// This doesn't work when scrolling
// let timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update", userInfo: nil, repeats: true)

// Do these two lines instead:
let timer = NSTimer(timeInterval: 1, target: self, selector: "update", userInfo: nil, repeats: true)

NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
}

func update() {
count += 1
timerLabel.text = "\(count)"
}
}

Swift 3:

let timer = Timer(timeInterval: 1, target: self, selector: #selector(update), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)

Swift 4, 5:

let timer = Timer(timeInterval: 1, target: self, selector: #selector(update), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)

UIScrollView pauses NSTimer until scrolling finishes

An easy & simple to implement solution is to do:

NSTimer *timer = [NSTimer timerWithTimeInterval:... 
target:...
selector:....
userInfo:...
repeats:...];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

UIScrollView pauses NSTimer while scrolling

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.

Weird Bug or Issue using Timer and ScrollView together

From The ultimate guide to Timer:

Working with runloops

One common problem folks hit when using timers is that they won’t fire
when the user is interacting with your app. For example, if the user
has their finger touching the screen so they can scroll through a
table view, your regular timers won’t get fired.

This happens because we’re implicitly creating our timer on the
defaultRunLoopMode, which is effectively the main thread of our
application. This will then get paused while the user is actively
interacting with our UI, then reactivated when they stop.

The easiest solution is to create the timer without scheduling it
directly, then add it by hand to a runloop of your choosing. In this
case, .common is the one we want: it allows our timers to fire even
when the UI is being used.

A solution is to run your timer on the RunLoop in the common mode:

func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerFunction), userInfo: nil, repeats: true)
RunLoop.current.add(timer, forMode: .common) // add this line
}

NSTimer not fired when uiscrollview event occurs

iOS Applications run on an NSRunLoop. Each NSRunLoop has different modes of execution for different tasks. For example, the default nstimer is scheduled to run under the NSDefaultRunMode on the NSRunLoop. What this means however is that certain UIEvents, scrollviewing being one, will interrupt the timer, and place it on a queue to be run as soon as the event stops updating. In your case, in order to get the timer to not be interrupted, you need to schedule it for a different mode, namely NSRunLoopCommonModes, like so:

  self.myTimer =  [NSTimer scheduledTimerWithTimeInterval:280
target:self
selector:@selector(doStuff)
userInfo:nil
repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:self.myTimer forMode:NSRunLoopCommonModes];

This mode will allow your timer to not be interrupted by scrolling.
You can find more about this info here: https://developer.apple.com/documentation/foundation/nsrunloop
At the bottom you will see the definitions of the modes you can choose from. Also, legend has it, you can write your own custom modes, but few have ever lived to tell the tale im afraid.

Why timer stops when scrolling in UIWebView iPhone?

You have to add the timer to another RunLoopMode. Per default a timer is added to the NSDefaultRunLoopMode. That means that the timer is only executing when the app’s run loop is in NSDefaultRunLoopMode.

Now, when a user touches the screen (e.g. to scroll a UIScrollView) the run loop’s mode will be switched to NSEventTrackingRunLoopMode. And now, that the run loop is not in NSDefaultRunMode anymore, the timer will not execute. The ugly effect of that is, that timer is blocked whenever the user touches the screen. And that can be a looong time when the user is scrolling, because the timer is blocked until the scrolling completely stops. And when the user continues to scroll, the timer is blocked again.

Fortunately the solution to this problem is quite simple: You can add your timer to another NSRunLoopMode. When add the timer to NSRunLoopCommonModes it will execute in all run loop modes (that have been declared as a member of the set of “common” modes, to be precise). That means that the timer is not only working in NSDefaultRunLoopMode but also in NSEventTrackingRunLoopMode (when the user touches the screen).

So after you initialize your timer, add it to NSRunLoopCommonModes:

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


Related Topics



Leave a reply



Submit