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?