crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

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 }