AuthorIdentity.swift (1266B)
1 import CloudKit 2 import Foundation 3 4 /// Cache for the current iCloud user's record name. Persisted to 5 /// UserDefaults so `currentID` is non-nil on every launch after the first 6 /// successful CloudKit fetch — without this, a cold launch from a shared-game 7 /// notification can race the async `userRecordID()` call and treat the local 8 /// user's authorID as if it belonged to a remote peer. Refreshed on 9 /// account-change events from `CKSyncEngine`. 10 @MainActor 11 final class AuthorIdentity { 12 private static let storageKey = "AuthorIdentity.currentID" 13 14 private(set) var currentID: String? 15 private let storage: UserDefaults 16 17 init(storage: UserDefaults = .standard) { 18 self.storage = storage 19 currentID = storage.string(forKey: Self.storageKey) 20 } 21 22 /// Injects a known ID without hitting CloudKit or persistent storage — 23 /// use in unit tests only. 24 init(testing fixedID: String) { 25 self.storage = UserDefaults.standard 26 currentID = fixedID 27 } 28 29 func refresh(using container: CKContainer) async { 30 guard let recordID = try? await container.userRecordID() else { return } 31 let newID = recordID.recordName 32 currentID = newID 33 storage.set(newID, forKey: Self.storageKey) 34 } 35 }