Custom Progressbar doesn't update properly

This is frustrating… I created a custom Progressbar like this


class myProgressBar : UIView {
    private var zValue : CGFloat = 0.0
    private let progressLayer  = CALayer()
    private let backgroundMask = CAShapeLayer()

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupLayers()
    }
    override init(frame:CGRect) {
        super.init(frame:frame)
        setupLayers()
    }

    private func setupLayers() { layer.addSublayer(progressLayer) }

    override func layoutSubviews() {
        super.layoutSubviews()
        backgroundMask.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.bounds.size.height * 0.25).cgPath
        layer.mask          = backgroundMask
        update()
    }

    func update() {
        let progressRect = CGRect(origin: .zero, size: CGSize(width: self.bounds.size.width * zValue, height: self.bounds.size.height))
        progressLayer.frame           = progressRect
        progressLayer.backgroundColor = UIColor.green.cgColor
        progressLayer.needsDisplayOnBoundsChange = true

        print(progressRect)
    }

    public func setProgress(_ v:CGFloat) {
        zValue = v
        update()
    }

}

and the setProgress function is called with increasing values (0.00 to 1.00) at various times during another function. The print command in the update() function is called at the correct times, and with the correct values. But the “drawing” of the layer doesn’t happen then… it happens ONCE when the routine is complete… Not much use that way as a “progress bar” :frowning:

for j in(0...f!.count-1) {
   let pct = CGFloat(j+1)/CGFloat(f!.count)
   updateLoadProgress(pct)
  // the print command shows changing values here
   .... do some stuff
}
// but the control doesn't really update until here, 
// after its all done, which is too late


 private func updateLoadProgress(_ value:CGFloat) {
        loadProgress.setProgress(value)
        loadProgress.layer.setNeedsDisplay()
        loadProgress.layer.displayIfNeeded()
}

what a pain… the only way I could make it work… was to force the main function to run on a background thread, and update the progress bar on the main thread. For something like a progress bar, that should be “built in”

but at least I got it to work :slight_smile:

as far as I understand all UI runs on the main thread
while updates to controls might be “thread safe”, ie/ they wont kill your app, until the main thread can do the update the updates just get coalesced

so forcing the update onto the main thread makes sense it works

glad you figured that one out

AFAIK, unless you specify it, all UI updates run on the main thread.

Edit: Oh, I see you’re using CALayers… Have you tried

I actually switched back to UIProgressView, but the issues were the same… threads