Swift 5.6, iOS 15.5
I have a class that is responsible for handling Sign in with Apple.
class SignInWithApple: NSObject, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
private var view: UIView
init(_ view: UIView) {
self.view = view
}
}
This class implements the delegate methods from ASAuthorizationControllerPresentationContextProviding
This is defined by Apple as:
@available(iOS 13.0, *)
public protocol ASAuthorizationControllerPresentationContextProviding : NSObjectProtocol {
/** @abstract Return a view anchor that is most appropriate for athorization UI to be presented over. This view will be used as a hint if a credential provider requires user interaction.
*/
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor
}
The implementation of this looks as follows:
extension SignInWithApple {
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return view.window!
}
}
I added some compiler flags to have more strict MainActor
usage checking (making sure that things that are marked as MainActor are not being called from other threads). namely:
-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks
This however gives me the following issues:
If I leave the code as-is, I get a compiler error in the ASAuthorizationControllerPresentationContextProviding
implementation:
Property 'window' isolated to global actor 'MainActor' can not be referenced from this synchronous context
Which makes sense as window
should only be accessed from the main actor.
If however I change it and add MainActor
like this:
@MainActor func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return view.window!
}
This gives me a warning:
Instance method 'presentationAnchor(for:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'ASAuthorizationControllerPresentationContextProviding'
Which makes sense, because the protocol, nor the declared function inside the protocol are marked as MainActor
by Apple.
So my question: How do I get rid of the error and the warning?
From what I see, I think Apple's codebase is simply not ready for strict MainActor
enforcement.
For people out-there implementing strict concurrency.
The issue here is the fact that the
view
property is a var thus allowing a shared mutable state. The compiler is making sure you can't actually read and write the property at the same time from two different threads.Therefore you need to make you
view
property alet
so the compiler knows there is no risk of having two threads concurrently mutating the property.Yet you will probably face the same issue with the
window
property which is also avar
.So you need to inject a
UIWindow
into you service and make it a constant.Alternatively you can wait for Apple to make AuthenticationServices thread safe and automatically synchronized to the main thread.