I have a method that is used in several places of an app I'm working on. It's a method to check if remote push notifications are enabled or not. The method returns a value but as you may know currentUserNotificationSettings
was deprecated so now I'm using getNotificationSettings
.
The problem is the first returns a value and the latests uses a block. I want to still be able to return a value to avoid refactoring everything so I wrote the following but it's failing and I can't understand why...
Is this ok?!
public static var isRemoteEnabled: Bool {
var notificationSettings: UNNotificationSettings?
let semasphore = DispatchSemaphore(value: 2)
UNUserNotificationCenter.current().getNotificationSettings { setttings in
notificationSettings = setttings
semasphore.signal()
}
semasphore.wait()
guard let authorizationStatus = notificationSettings?.authorizationStatus else { return false }
return authorizationStatus == .authorized
}
Edited:
I followed @rmaddy comment and at least now it doesn't crash but it gets stuck in the wait()
. If I go to debugger and e semasphore.signal()
it completes and the app continues working fine. Somehow the completion block is not being called.
In a case like this you want the semaphore created with an initial value of 0
, not 2
.
let semasphore = DispatchSemaphore(value: 0)
This is mentioned in the documentation:
Passing zero for the value is useful for when two threads need to reconcile the completion of a particular event.
wait
first decrements the value. It then blocks until the value is greater or equal to 0. With your value of 2, it was decremented to 1 and since that is already greater or equal to 0, the wait
didn't need to block and your method returned long before the call to signal
.
There is also the chance that the completion block for getNotificationSettings
could be called on the same thread (causing a deadlock) so call it on a background queue.
public static var isRemoteEnabled: Bool {
var notificationSettings: UNNotificationSettings?
let semasphore = DispatchSemaphore(value: 0)
DispatchQueue.global().async {
UNUserNotificationCenter.current().getNotificationSettings { setttings in
notificationSettings = setttings
semasphore.signal()
}
}
semasphore.wait()
guard let authorizationStatus = notificationSettings?.authorizationStatus else { return false }
return authorizationStatus == .authorized
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With