I have a working app with core data and cloudkit. I changed the NSPersistentContainer to NSPersistentCloudKitContainer. Two NSManagedObjects 'Contact' and 'Location' already exist in core data with relationships along with some other related NSManagedObjects. Populated core data in 'Contact' and saved. Logged in to CloudKit to see it had created CD_Contact and CD_Location CKRecords along with some other CKRecords. Queried CD_Contact it gave error - index name not available on recordName. So created an Index of type Queryable on recordName and searched again. There is no data in CD_Contact.
It is supposed to sync data from core data to cloud Kit, but only CKRecord is created but data saved in core data is not synced and populated in CloudKit. How to fix this? On debug I get this:
"<CKRecord: 0x104f0afc0; recordType=CD_Contact, recordID=558FD3FB-A293-444C-8894-A1A7B786D73A:(com.apple.coredata.cloudkit.zone:__defaultOwner__), recordChangeTag=15, values={\n \"CD_assignedEEP\" = 0;\n \"CD_createdDate\" = \"2022-11-03 04:14:17 +0000\";\n \"CD_email\" = \"crsp@gmail\";\n \"CD_entityName\" = Contact;\n \"CD_firstName\" = chaya;\n \"CD_imageName\" = \"{ length=87143, sha256=ed66d0026ea41aed08e213928643398504dea984c010b80a8852a0fb72c80350 }\";\n \"CD_lastName\" = rao;\n \"CD_me\" = 0;\n \"CD_orgName\" = \"\";\n \"CD_phone\" = 8327292039;\n \"CD_screenName\" = cvr;\n \"CD_uniqueId\" = \"A2469E8D-782F-49F5-8186-3C38B8F9B715-55813-00001051FEDEEF2F\";\n \"CD_userRating\" = \"Not rated\";\n \"CD_userType\" = \"Consumer & Producer(Household)\";\n}>",
"CD_contactEmail" = "crsp@gmail";
"CD_contactEmail_ckAsset",
"CD_contact",
"CD_contactEmail",
"<CKRecord: 0x111659350; recordType=CD_Location, recordID=D6FA5778-587E-4778-925E-197AD5ABC66B:(com.apple.coredata.cloudkit.zone:__defaultOwner__), recordChangeTag=19, values={\n \"CD_apt\" = \"\";\n \"CD_assignedEEP\" = 0;\n \"CD_batterykWh\" = 0;\n \"CD_city\" = Houston;\n \"CD_contactEmail\" = \"crsp@gmail\";\n \"CD_country\" = US;\n \"CD_entityName\" = Location;\n \"CD_evkWh\" = 0;\n \"CD_latitude\" = \"29.92885756496788\";\n \"CD_loadWatts\" = 0;\n \"CD_loadkWh\" = 0;\n \"CD_locationName\" = myloc;\n \"CD_locationType\" = Household;\n \"CD_longitude\" = \"-95.60777006842892\";\n \"CD_netMeterEsid\" = 1008901023808105650100;\n \"CD_provider\" = \"AMIGO ENERGY\";\n \"CD_providerType\" = \"Energy Provider\";\n \"CD_solarkWh\" = 0;\n \"CD_state\" = TX;\n \"CD_street\" = \"11202 Hillside Glen Trail \";\n \"CD_uniqueId\" = \"27D61490-B38A-4F0A-A5EC-76BDBDEBA46F-55813-00001052B902170C\";\n \"CD_windkWh\" = 0;\n \"CD_zip\" = 77065;\n}>"
My AppDelegate Code:
let container = NSPersistentCloudKitContainer(name: "MyModel")
let defaultStoreURL = try! FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("MyModel.xcdatamodeld")
let description = NSPersistentStoreDescription(url: defaultStoreURL)
let cloudkitOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.com.ggp.nr")
description.cloudKitContainerOptions = cloudkitOptions
let remoteChangeKey = "NSPersistentStoreRemoteChangeNotificationOptionKey"
description.setOption(true as NSNumber,
forKey: remoteChangeKey)
description.setOption(true as NSNumber,
forKey: NSPersistentHistoryTrackingKey)
container.persistentStoreDescriptions = [description]
container.viewContext.automaticallyMergesChangesFromParent = true
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
// if FileManager.default.fileExists(atPath: self.storeURL.path) {
// self.duplicateRecordsAndDeleteOldStore(newContext: container.newBackgroundContext(), mom: container.managedObjectModel)
// }
})
return container
}()
Also in my cloudKit database "iCloud.com.ggp.nr", under security roles for iCloud and World I have set Read and Write permissions for all the CD_ Records.
Don't know what else to do. Any help is appreciated.
Post
Replies
Boosts
Views
Activity
I have timer based code running perfectly when the app is running. Both the timer based functions get called and I am able to access and update iCloud. But if accidentally app goes off-line or user kills it, the timer code cannot be invoked. Is there a off-line mechanism, or some technique anyone can suggest that will allow to recollect and invoke pre-defined timer calls and execute the associated code?
let currentDateTime = Date()
let calendar = Calendar.current
var tempDateTime1 = calendar.date(byAdding: .minute, value: 1, to: currentDateTime)
var tempDateTime2 = calendar.date(byAdding: .minute, value: 2, to: currentDateTime)
DispatchQueue.main.async {
let userInfo:Dictionary<String, String> = ["tag": orderCkRecordName]
let startTimer = Timer(fireAt: tempDateTime1!, interval: 0.0, target: self, selector: #selector(self.beginOrderUpdate(sender:)), userInfo: userInfo as Dictionary, repeats: false)
let endTimer = Timer(fireAt: tempDateTime2!, interval: 0.0, target: self, selector: #selector(self.endOrderUpdate(sender:)), userInfo: userInfo as Dictionary, repeats: false)
RunLoop.current.add(startTimer, forMode: RunLoopMode.commonModes)
RunLoop.current.add(endTimer, forMode: RunLoopMode.commonModes)
}
in Cloudkit Dashboard, I select Record Type, Edit Indexes, then I select Add Basic Index. I see createTime, createdBy, eTag, modTime, modifiedBy, recordID. I do not see recordName. Without creating index on recordName, I cannot query the record in cloudKit Dashboard. How to create index on recordName??
I drag a scroll view and then set constraint 0 on all four directions. I cannot activate update frame. Gives error ScrollView has ambiguous scalable content width and height
while presenting the UICloudSharingController on top of a view, it presents the screen and when I select the messages option to send a message to a person whom I want to share with, it gives a spinning wheel with "uploading" message and vanishes.
However when I go to cloudkit dashboard the root record has been shared. But I cannot share it with specific person. Is it because it has shared global? How can I fix it?
self.shareInfraRecord(zoneID: appDelegate.privateContactZoneID, completion: { (status) in
		 if ( status == false) {
						 return
			}
		})
func shareInfraRecord(zoneID: CKRecordZone.ID, completion: @escaping(Bool) -> Void) {
		if let rootRecord = self.rootRecord {
				if self.rootRecord?.share == nil {
						let sharingController = UICloudSharingController { (controller, preparationHandler: @escaping (CKShare?, CKContainer?, Error?) -> Void) in
								
								let shareID = CKRecord.ID(recordName: UUID().uuidString, zoneID: zoneID)
								var share = CKShare(rootRecord: rootRecord, shareID: shareID)
							
								share[CKShare.SystemFieldKey.title] = Cloud.ShareInfrastructure.ContactShareTitleKey as CKRecordValue?
								share[CKShare.SystemFieldKey.shareType] = Cloud.ShareInfrastructure.ContactShareTypeKey as CKRecordValue?
							
								let modifyRecZoneOp = CKModifyRecordsOperation(recordsToSave:[rootRecord, share], recordIDsToDelete: nil)
								modifyRecZoneOp.modifyRecordsCompletionBlock = { (records, recordID, error) in
										if error != nil {
												if let ckerror = error as? CKError {
														if let serverVersion = ckerror.serverRecord as? CKShare {
																share = serverVersion
														}
														completion(false)
												}
										}
										preparationHandler(share, self.defaultContainer, error)
								}
								self.privateDB?.add(modifyRecZoneOp)
						}
Upgraded ios 13.6 and changed bundle identifier and container name. Created CKDatabaseSubscription for both public and shared database and can see in cloudkit dashboard. Both didFinishLaunchingWithOptions and didRegisterForRemoteNotificationsWithDeviceToken get called in AppDelegate.
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { granted, error in
guard granted else { return }
DispatchQueue.main.async {
application.registerForRemoteNotifications()
print("Registered for Remote notifications")
}
})
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data){
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: \(token)")
})
self.iCloudSubscribeToPrivateDB()
self.iCloudSubscribeToSharedDB()
}
In the project both background fetch and remote notifications are enabled. I make databases changes in cloudkit dashboard, but push notifications are not being sent. They were working now just stopped after I made the above changes. What could be wrong?
I create a share and the shared URL is successfully created
let share = CKShare(rootRecord: infraRecord)
// save
let op: CKFetchShareParticipantsOperation = CKFetchShareParticipantsOperation(userIdentityLookupInfos: lookupInfos)
op.fetchShareParticipantsCompletionBlock = { error in
if let error = error {
print("error: ", error)
completion(false, error)
}
}
op.shareParticipantFetchedBlock = { participant in
participant.permission = .readOnly
share.addParticipant(participant)
let modOp: CKModifyRecordsOperation = CKModifyRecordsOperation(recordsToSave: [infraRecord, share], recordIDsToDelete: nil)
modOp.savePolicy = .ifServerRecordUnchanged
modOp.perRecordCompletionBlock = {record, error in
print("record completion \(record) and \(String(describing: error))")
}
modOp.modifyRecordsCompletionBlock = {records, recordIDs, error in
if let error = error {
print("error in modifying the records: ", error)
}
else if let anURL = share.url {
// update the location CKRecord with share URL
self.updateLocationPublicRecord(withShareUrl: anURL.absoluteString, locationRecord: locationRecord, completion: { (status, error) in
if let error = error {
print("error: ", error)
}
})
print("share url \(String(describing: share.url))")
}
completion(true, nil)
}
self.privateDB?.add(modOp)
//completion(true, nil)
}
self.defaultContainer?.add(op)
To access the share I first try to get the recordzones from shared database
func getRecordZones(completion: @escaping (CKRecordZoneID?, Error?) -> Void) {
self.sharedDB?.fetchAllRecordZones(completionHandler: { (ckrecordZones, error) in
guard error == nil else {
if let ckError = error as? CKError {
self.aErrorHandler.handleCkError(ckerror: ckError)
}
completion (nil, error)
return
}
if let recordZones = ckrecordZones {
for i in 0 ..< recordZones.count{
// find the zone you want to query
if recordZones[i].zoneID.zoneName == Cloud.SharedZone.UserProfile.ZoneName {
completion (recordZones[i].zoneID, nil)
}
}
}
})
}
```
I dont get any recordzones from shared database. When I go to cloudkit dashboard, I don't see any shared zones in the shared database. Why is it that shared record zone does not exist? how to make this work?
I have only one phone and Apple ID. I want to test CKShare between two users. Do I need two phones? Do I need two different Apple IDs? I read that two Apple IDs cannot share same phone. Can someone tell me what is the best way to test CKShare between two users on my development environment