'Establishing a User' - CloudKit Discoverability Deprecated.

My App uses Core Data + CloudKit and requires use of CloudKit to store persistent data, that will be shared between Users. I’d like to establish the User’s identity - like so they can augment their Core Data ‘Player’ entity w/ App specific info. Certain interfaces have been deprecated (‘user discoverability’). I’ve taken to creating a ‘dummy shared zone’ and extracting the ‘owner.userIdentity':

public func establishUser () async -> User? {
    let container  = cloudKitContainer

    // If we store the userUUID then the implication is that the `user` can 
    // never be deleted; that is fair enough.

    let userUUIDKey   = "userUUID"
    var userIdentity  = Optional<CKUserIdentity>.none

    do {

        //
        // We'll store the UUID of the CoreData `User` in the CloudKit `User` record.  If there
        // is no UUID in CloudKit, then this will be the first time the User has ever started
        // the App.  We'll create a user and update the CloudKit `User` record
        //

        let userID       = try await container.userRecordID ()
        let userRecord   = try await container.publicCloudDatabase.record (for: userID)

        // If the `userRecord` does not have a `userUUIDKey` then we must create a new `User`.
        if nil == userRecord[userUUIDKey] {

            // See if the user has the required iCloud account.
            let userStatus = try await container.accountStatus()

            guard userStatus == .available
            else {
                print ("JKP: \(#function) accountStatus: \(userStatus)")
                return nil
            }

            //
            // Create a `dummyShare` (in a 'dummyZone') so we can access the share's owner
            // That owner will have our `userIdentity`
            //

            do {
                let dummyZone     = CKRecordZone (zoneName: UUID().uuidString)
                let dummyShare    = CKShare (recordZoneID: dummyZone.zoneID)

                print ("JKP: User: Establish Zone: \(dummyZone.zoneID.zoneName)")

                // Save the dummyZone and then the dummyShare (for/in the dummyZone)
                let _ = try await container.privateCloudDatabase.save (dummyZone)
                let _ = try await container.privateCloudDatabase.save (dummyShare)

                // Extract the dummyShare's owner's identity - which is 'us/me'
                userIdentity = dummyShare.owner.userIdentity

                // Cleanup by deleting the 'dummyShare' and then the 'dummyZone'
                let _ = try await container.privateCloudDatabase.deleteRecord (withID: dummyShare.recordID)
                let _ = try await container.privateCloudDatabase.deleteRecordZone (withID: dummyZone.zoneID)
            }
            catch {
                print ("JKP: User Establish Error: \(error.localizedDescription)")
            }

            // Create `newUser` with the `userRecordId`.  We'll use this to lookup the
            // Core Data User when players appear in a League.
            let newUser = User.create (context,
                                       scope: Player.Scope.owner,
                                       name: (userIdentity?.nameComponents ?? PersistenceController.nameDefault),
                                       identification: userIdentity?.lookupInfo
                                           .map { PlayerIdentification.create (lookupInfo: $0) } ?? PlayerIdentification())

… }

Is this how getting the userIdentity is meant to be done (w/o using the deprecated interfaces)? The deprecated interfaces, when warned in Xcode, reference a sample project; that project doesn’t actually use/get the userIdentity.

Also the deleteRecord and deleteRecordZone don’t appear to remove the dummy zone in CloudKit; why?

  • This approach, of mine, is nonsense as regards use of the 'UserRecord.' Rather than storing a UUID somewhere and then looking up that UUID in the CoreData just 1) wait for the CoreData to by synced from iCloud (e.g. use the 'import success' event) and then 2) filter all Users for 'is owner' (or some such flag). Still need to get the userIdentity and using a dummy{Zone|Share} seems suspect. Hopefully somebody knows the preferred approach.

Add a Comment