Swift - UIProgressView is not smooth with NSTimer

Therefore, I use NSTimer so that the user knows that the application is running. The progress bar is set to 3 seconds, but when it starts, it appears in the "tick" mode, and it is not as smooth as it should be. In any case, I can make it smoother - I'm sure it's just a calculation error on my part ....

If anyone could take a look, that would be great. Here is the code:

import UIKit class LoadingScreen: UIViewController { var time : Float = 0.0 var timer: NSTimer? @IBOutlet weak var progressView: UIProgressView! override func viewDidLoad() { super.viewDidLoad() // Do stuff timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector:Selector("setProgress"), userInfo: nil, repeats: true) }//close viewDidLoad func setProgress() { time += 0.1 progressView.progress = time / 3 if time >= 3 { timer!.invalidate() } } } 
+8
ios swift uiprogressview
source share
4 answers

Edit: simple 3 second UIView animation (recommended)

If your panel simply moves smoothly to indicate activity, perhaps consider using a UIActivityIndicatorView or a custom UIView animation:

 override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) UIView.animateWithDuration(3, animations: { () -> Void in self.progressView.setProgress(1.0, animated: true) }) } 

First of all, make sure that progress progress progress is set to zero. This will result in a smooth 3-second progress animation.

Simple animated move (works, but still jumps a bit)

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIProgressView_Class/#//apple_ref/occ/instm/UIProgressView/setProgress:animated :

 func setProgress() { time += 0.1 progressView.setProgress(time / 3, animated: true) if time >= 3 { timer!.invalidate() } } 

Option at shorter intervals. (Not recommended)

Set the timer to a shorter interval:

 timer = NSTimer.scheduledTimerWithTimeInterval(0.001, target: self, selector:Selector("setProgress"), userInfo: nil, repeats: true) 

Then update your function

 func setProgress() { time += 0.001 progressView.setProgress(time / 3, animated: true) if time >= 3 { timer!.invalidate() } } 
+18
source share

How about the correct way to animate changes: animateWithDuration: animations: or CABasicAnimation . You can use this to create smooth animations.

+2
source share

It’s hard to say what the problem is. I would like to see the output if you put the print string in setProgress to print the timestamp. Does he really shoot every tenth of a second? I guess that is not the case.

Why not? Well, a timer plans to execute a loop in the main thread to execute code in setProgress. This task cannot be performed until tasks in front of it in the queue are completed. Therefore, if long tasks are performed in your main thread, your timer will work very inaccurately. My first suggestion is that this is possibly what is happening.

Here is an example:

  • You start a timer to do something every second.
  • Immediately after that, you start working with a large number of tasks of the main stream (for example, you are trying to write a ton of data to a file). This task will take five seconds.
  • Your timer wants to start after one second, but your write to the file clogging the main stream for the next four seconds, so the timer cannot be triggered for another four seconds.

If this is the case, then to solve the problem you will need to either move this main thread to the background thread, or figure out how to execute it, periodically returning to the start loop. For example, during a lengthy main thread operation, you can periodically call runUntilDate in a run loop to perform other tasks in the run loop.

Please note that you could not simply increase the number of progress indicators during the long execution of the main thread task, because the progress indicator does not actually activate its filling until you return to the execution cycle.

+1
source share

To continue the bootloader

 timer = Timer.scheduledTimer(timeInterval: 0.001, target: self, selector: #selector(setProgress), userInfo: nil, repeats: true) 

and

 func setProgress() { time += 0.001 downloadProgressBar.setProgress(time / 3, animated: true) if time >= 3 { self.time = 0.001 downloadProgressBar.progress = 0 let color = self.downloadProgressBar.progressTintColor self.downloadProgressBar.progressTintColor = self.downloadProgressBar.trackTintColor self.downloadProgressBar.trackTintColor = color } 
0
source share

All Articles