I'm building an app where the user can press play and then the app will scroll through some musical notes (like sheet music). I use a timer and counter to move the view along. The code works ok, except that every time I press play to start the view scrolls at a different speed. The first time is very slow but it gets to the speed I want after playing through a few times. I assume this is because as I repeat the action, iOS loads things into memory and is able to run things faster and smoother.

Is there some way to speed things up, or perhaps there is a different approach than using a UIScrollView for something it wasn't really designed for? Any ideas are much appreciated!

import UIKit

class TimelineViewController: UIViewController {

var screenHeight = UIScreen.main.bounds.height
var screenWidth = UIScreen.main.bounds.width
var scrollView = UIScrollView()
let canvasWidth = 7204
var counter = 0
var timer = Timer()

func setupScrollView() {
    scrollView.frame = self.view.bounds
    let scrollImageView = UIView()
    scrollImageView.frame = CGRect(x: 0, y: 0, width: canvasWidth, height: Int(screenHeight))
    scrollView.contentSize = scrollImageView.bounds.size
    scrollView.showsHorizontalScrollIndicator = false
    scrollView.showsVerticalScrollIndicator = false
    scrollView.backgroundColor = .black

@objc func updateTime() {
    DispatchQueue.global(qos: .default).async {
        let counterStop = self.canvasWidth-(Int(self.screenWidth))
        guard self.counter < counterStop else {return}
        self.counter += 1

    UIView.animate(withDuration: 0.1, animations: {
        self.scrollView.setContentOffset(CGPoint(x: self.counter, y: 0), animated: false)

@IBAction func startPlayhead(_ sender: Any) {
    print("Play pressed")
    counter = 0
    let tempoSetter = 0.03
    timer = Timer.scheduledTimer(timeInterval: tempoSetter, target: self, selector: #selector(updateTime), userInfo: nil, repeats: true)

override func viewDidLoad() {
    var measureMarkerCoords: [Int] = [600,1200,1800,2400,3000,3600,4200, 4800, 5400, 6000, 6600,7200]
    var colourOrder: [UIColor] = [UIColor.red,UIColor.orange, UIColor.yellow, UIColor.green, UIColor.blue, UIColor.purple, UIColor.red,UIColor.orange, UIColor.yellow, UIColor.green, UIColor.blue, UIColor.purple]

    for i in 0...11 {
        let measureMarker = UIView(frame:CGRect(x:measureMarkerCoords[i],y:0,width:4,height:Int(screenHeight)))
        measureMarker.backgroundColor = colourOrder[i]

    let playButton = UIButton(frame: CGRect(x: 10, y: 5, width: 44, height: 44))
    playButton.setTitle("Play", for: .normal)
    playButton.addTarget(self, action: #selector(startPlayhead(_:)), for: .touchUpInside)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.