iosswiftasynchronousdispatchsemaphore

Dispatch Semaphore for UI


I wanted to animate the alpha of uiviews and i cannot seem to make it. It behaves weirdly and says error that running UI changes arent recommended to be run on background thread, but I dont know how do I make it run on the main one. Can somebody help me? I believe it skips the first UIView.animate block and performs whats in the second without any animation whatsoever.

func animateSemaphore() {

circleRed.alpha = 0.2
circleOrange.alpha = 0.2
circleGreen.alpha = 1

let dispatchSemaphore = DispatchSemaphore(value: 0)
let dispatchQueue = DispatchQueue.global(qos: .background)

dispatchQueue.async {
    UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
        self.circleOrange.alpha = 1
        self.circleGreen.alpha = 0.2
    } completion: { (_) in
        print("1")
        dispatchSemaphore.signal()
    }
    
    dispatchSemaphore.wait()
    UIView.animate(withDuration: 0.5, delay: 3, options: .curveEaseInOut) {
        self.circleOrange.alpha = 0.2
        self.circleRed.alpha = 1
    } completion: { (_) in
        dispatchSemaphore.signal()
    }
    
    dispatchSemaphore.wait()
    UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
        self.circleOrange.alpha = 1
    } completion: { (_) in
        dispatchSemaphore.signal()
    }
    
    dispatchSemaphore.wait()
    UIView.animate(withDuration: 0.5, delay: 1, options: .curveEaseInOut) {
        self.circleOrange.alpha = 0.2
        self.circleRed.alpha = 0.2
        self.circleGreen.alpha = 1
    } completion: { (_) in
        self.animateSemaphore()
    }
}

}


Solution

  • You need to insert any ui/animate related code inside main thread not inside a background queue

    func animateSemaphore() {
        circleRed.alpha = 0.2
        circleOrange.alpha = 0.2
        circleGreen.alpha = 1
            
        UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
            self.circleOrange.alpha = 1
            self.circleGreen.alpha = 0.2
        } completion: { (_) in
            UIView.animate(withDuration: 0.5, delay: 3, options: .curveEaseInOut) {
                self.circleOrange.alpha = 0.2
                self.circleRed.alpha = 1
            } completion: { (_) in
                UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
                    self.circleOrange.alpha = 1
                } completion: { (_) in
                    UIView.animate(withDuration: 0.5, delay: 1, options: .curveEaseInOut) {
                        self.circleOrange.alpha = 0.2
                        self.circleRed.alpha = 0.2
                        self.circleGreen.alpha = 1
                    } completion: { (_) in 
                    }
                }
            }
        }
     }
    

    OR play with delay instead of nesting animations

    func animateSemaphore() {
    
        circleRed.alpha = 0.2
        circleOrange.alpha = 0.2
        circleGreen.alpha = 1
    
        UIView.animate(withDuration: 0.5, delay: 5, options: .curveEaseInOut) {
            self.circleOrange.alpha = 1
            self.circleGreen.alpha = 0.2
        } completion: { (_) in
            print("1")
          
        }
        
       
        UIView.animate(withDuration: 0.5, delay: 8.5, options: .curveEaseInOut) {
            self.circleOrange.alpha = 0.2
            self.circleRed.alpha = 1
        } completion: { (_) in
            
        }
        
       
        UIView.animate(withDuration: 0.5, delay: 14, options: .curveEaseInOut) {
            self.circleOrange.alpha = 1
        } completion: { (_) in
           
        }
        
      
        UIView.animate(withDuration: 0.5, delay: 15.5, options: .curveEaseInOut) {
            self.circleOrange.alpha = 0.2
            self.circleRed.alpha = 0.2
            self.circleGreen.alpha = 1
        } completion: { (_) in
            
        }
    }