AppleBee
AppleBee

Reputation: 1219

can I call on semaphore.wait() main thread?

I have a method which gives me photo auth status.

func photosAuthorizationStatus() -> PHAuthorizationStatus {
        var authStatus = PHAuthorizationStatus.notDetermined
        let semaphore = DispatchSemaphore(value: 0)
        PHPhotoLibrary.requestAuthorization { (status: PHAuthorizationStatus) in
            authStatus = status
            semaphore.signal()
        }
        semaphore.wait()
        return authStatus
    }

I am calling this method in viewDidAppear of a ViewController , but Application is not freezing.

But if I call semaphore.wait when I ask mainQueue explicitly Application is freezing.

DispatchQueue.main.async{
let semaphore = DispatchSemaphore(value: 0)
semaphore.wait()

}

// Above code will freeze the application.

Can I know the reason ?

Upvotes: 2

Views: 5125

Answers (3)

Karoly Nyisztor
Karoly Nyisztor

Reputation: 3595

A bit late to the party, but it may be useful for others, since nobody explained the real issue here.

Calling semaphore.wait() decreases the counting semaphore. If the counter becomes smaller than zero, wait() blocks the main queue until you signal the semaphore.

Now, you invoke semaphore.signal() in the completion closure, which happens to execute on the main queue. But the main queue is blocked, so it won't call semaphore.signal(). wait() and signal() will wait for each other for eternity -> a guaranteed classic deadlock!

Forget the semaphore, and refactor the photosAuthorizationStatus() method to return the result via a closure, as suggested by Sagar Chauhan.

Upvotes: 1

Rob
Rob

Reputation: 437552

In your title, you ask:

can I call on semaphore.wait() main thread?

You should avoid blocking the main thread for any reason. Whether wait for semaphores or dispatch groups, or even synchronously dispatching (e.g., sync) of anything more than a few milliseconds. You risk having the watchdog process kill your app if you do this at the wrong time, and it results in a horrible UX.


You then go on to ask:

DispatchQueue.main.async {
   let semaphore = DispatchSemaphore(value: 0)
   semaphore.wait()
}

Above code will freeze the application.

Can I know the reason

That code says “block the main thread waiting for a signal on this semaphore”. So, until that signal arrives, the main thread will be blocked. But the main thread should never be blocked because it services, amongst other things, the UI, and your app will freeze if you deadlock the main thread.

Bottom line, never block the main thread.

Upvotes: 3

Sagar Chauhan
Sagar Chauhan

Reputation: 5823

Create completion closure in method which will call after successful request authorisation completed. See following code.

Make sure your have added permission key "Privacy - Photo Library Usage Description" in Info.plist file.

func photosAuthorizationStatus(completion: @escaping (PHAuthorizationStatus) -> Void) {
    PHPhotoLibrary.requestAuthorization { (status: PHAuthorizationStatus) in
        completion(status)
    }
}

Use:

self.photosAuthorizationStatus { (status) in
    // use your status here
}

Output:

enter image description here

Upvotes: 1

Related Questions