kaandedeoglu / KDCircularProgress

A circular progress view with gradients written in Swift
MIT License
1.21k stars 217 forks source link

App crashing when calling progress() from async thread #11

Closed sneps85 closed 8 years ago

sneps85 commented 9 years ago

My app is crashing when calling progress() and finished from async thread, as the progressLayer.presentationLayer() is nil.

Is that an issue of KDCircularProgress or am I doing something wrong?

kaandedeoglu commented 9 years ago

I've never had such issues, are you sure you're touching KDCircularProgress only on the main thread?

sneps85 commented 9 years ago

I start Kdcircularprogress, then i make an Alamofire request. In the success callback i have to do some async calculation (dispatch_async) in a for loop, for which i am using the kdcircularprogress. Therefore i call progress() inside this loop and finished() after the loop. But when i do not check if the progressLayer.presentationLayer() exists inside the progress() call before calling animateToAngle() (duration 0.02), the app crashes. I think this happens because somehow finished() is executed before one of the last animateToAngle call

kaandedeoglu commented 9 years ago

Okay I see.

To further understand the root of this, can I see a crash log and your sample code please?

sneps85 commented 9 years ago

I updated the comment above. I do not have access to the code right know, i can give it to you on monday. But i think the description above explains the procedure quite good.

sneps85 commented 9 years ago

Here a pseudocode:

Circularprogress.started() Response Handler

Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"]) .response { request, response, data, error in dispatch_async { for (index, row) in data { Calc() Circularprogress.progress(percentage: index/row.count) } Circularprogress.finished() } }

kaandedeoglu commented 9 years ago

here's the problem, you must switch back to the main thread before calling any of the CircularProgress' methods.

    dispatch_async(dispatch_get_main_queue()) {
        Circularprogress.progress(...) // and so on
    }

This applies for any code that calls any UIKit method

sneps85 commented 9 years ago

But how to do that? I get the percentage only in the async thread... Could you help me?

sneps85 commented 9 years ago

for now, my workaround is to check if processLayer.presentationLayer() is not nil before calling animateToAngle() in progress()...

sneps85 commented 9 years ago

No i have access to the code and i didn't remember, but inside of the progress(), finished() and started() methods, i do:

dispatch_async(dispatch_get_main_queue()) { ... }

here the code:

func started() {
    dispatch_async(dispatch_get_main_queue()) {
        self.backgroundImageView!.alpha = 1.0
        self.backgroundView = self.backgroundImageView
    }
}

func progress(percent:Int, description:String?=nil) {
    dispatch_async(dispatch_get_main_queue()) {
        if (self.backgroundImageView.progressIndicatorView.layer.presentationLayer() != nil) {
            let newAngleValue = Int((360 * percent) / 100 )
            if (self.backgroundImageView.progressIndicatorView.angle != newAngleValue) {
                self.backgroundImageView.progressIndicatorView.animateToAngle(newAngleValue, duration: 0.02, completion: nil)
            }
        }
    }
}

func error(message:String?) {
    dispatch_async(dispatch_get_main_queue()) {
    }
}

func finished() {
    dispatch_async(dispatch_get_main_queue()) {
        self.backgroundImageView.alpha = 0.0
        self.backgroundView = self.backgroundImageView
    }
}

but anyway i have to check

        if (self.backgroundImageView.progressIndicatorView.layer.presentationLayer() != nil)

otherwise the app crashes...