로그인 기능을 구현한다.
Supabase 환경 설정은 아래 글에서 확인할 수 있습니다. 이 글에서는 그외 환경설정을 다룹니다.
Xcode Signing & Capabilities > + Capability 에서 Sign In with Apple을 활성화합니다.

만약 Automatically manage signing이 아닌 프로비저닝 파일을 따로 사용하고 있는 경우에는
Apple Developer > Identifiers 에서 해당 앱 번들 ID에서 Sign In with Apple을 활성화한 후 프로비저닝 파일을 재다운로드, import 해야 정상적으로 컴파일됩니다.
로그인에 대한 결과는 델리게이트 패턴으로 받아볼 수 있습니다. 사용의 편의를 위해 Swift Concurrency 방식으로 래핑하는 작업을 거쳤습니다.
import AuthenticationServices
final class AppleAuthManager: NSObject, AppleAuthManageable {
/// ,,, 중략
#if DEBUG
private var continuation: CheckedContinuation<String, Error>?
#else
private var continuation: UnsafeContinuation<String, Error>?
#endif
func signIn() async throws -> String {
let request = provider.createRequest()
authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController?.delegate = self
authorizationController?.presentationContextProvider = self
authorizationController?.performRequests()
#if DEBUG
let idToken = try await withCheckedThrowingContinuation { [weak self] continuation in
self?.continuation = continuation
}
#else
let idToken = try await withUnsafeThrowingContinuation { [weak self] continuation in
self?.continuation = continuation
}
#endif
continuation = nil
return idToken
}
}
extension AppleAuthManager: ASAuthorizationControllerDelegate {
func authorizationController(
controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization
) {
guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential,
let idTokenData = credential.identityToken,
let idToken = String(data: idTokenData, encoding: .utf8) else {
continuation?.resume(throwing: AppleAuthError.idTokenNotFound)
return
}
continuation?.resume(returning: idToken)
}
func authorizationController(
controller: ASAuthorizationController,
didCompleteWithError error: any Error
) {
continuation?.resume(throwing: AppleAuthError.signInFailed)
}
}
DEBUG 모드 에서는 CheckedContinuation, RELEASE 모드에서는 UnsafeContinuation을 사용하고 있습니다. CheckedContinuation은 런타임시 resume이 여러번 호출되는지 확인합니다.
UnsafeContinuationavoids enforcing these invariants at runtime because it aims to be a low-overhead mechanism for interfacing Swift tasks with event loops, delegate methods, callbacks, and other non-asyncscheduling mechanisms. However, during development, the ability to verify that the invariants are being upheld in testing is important.
CheckedContinuation은 resume이 두번 이상 호출될 시 앱 크래시를 발생시킵니다. 이에 비해 UnsafeContinuation은 오버헤드가 적습니다. 리소스 낭비로 이어질 수는 있지만, 앱 크래시가 발생하지는 않기 때문에 해당 코드를 모드에 따라 분기처리했습니다.