Sign in with Apple MainActor issues

336 Views Asked by At

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.

1

There are 1 best solutions below

2
On

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 a let 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 a var.

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.