Using Ckcloud Kit to Share Private Records

I am using the following code to attempt to create a shared private record:

@IBAction func testPress(_ sender: Any) {

    let customZone = CKRecordZone(zoneName: "ShareZone")
    let friendRecord = CKRecord(recordType: "Share", zoneID: customZone.zoneID)
    let rootRecord = CKRecord(recordType: "Root", zoneID: customZone.zoneID)

    model.privateDB.delete(withRecordZoneID: customZone.zoneID) { (nil, error) in
        self.model.privateDB.save(customZone) { (nil, error) in
            print("Custom Zone Error = \(error)")
            self.model.privateDB.save(friendRecord, completionHandler: { (nil, error) in
                self.model.privateDB.save(rootRecord, completionHandler: { (nil, error) in
                    self.shareTest(record: friendRecord, root: rootRecord)
                })
            })
        }
    }
}

func shareTest(record:CKRecord, root:CKRecord) {

    record["Name"] = "Test" as CKRecordValue?
    root["Name"] = "Test" as CKRecordValue?

    let ckContainer = CKContainer.default()
    let shareRecord = CKShare(rootRecord: root, share: record.recordID)

    shareRecord[CKShareTitleKey] = "Name" as CKRecordValue?

    let shareController = UICloudSharingController(share: shareRecord, container: ckContainer)
    shareController.delegate = self
    shareController.availablePermissions = [.allowReadOnly]

    self.present(shareController, animated: false)
}

However I am returning the error when I press on a way to share the link:

CKError 0x6000002535f0: "Invalid Arguments" (12); "An added share is being saved without its rootRecord (CKRecordID: 0x608000224560; recordName=C0ADC819-57F7-4D99-A527-B21590F506AB, zoneID=ShareZone:defaultOwner)"

I looked at this answer Link who was having the same problem, but do not quite know how to get their solution to work as they didn't provide enough details.

Does anyone know what I am doing wrong?

1 Answer

I believe the error message is telling you need to save the share and root record at the same time.

let modifyRecordsOperation = CKModifyRecordsOperation( recordsToSave: [record, share], recordIDsToDelete: nil)

You should do this operation in the completion handler of the sharingController.

sharingController = UICloudSharingController {
                        controller, preparationCompletionHandler in

Edit: Your code would look something like this not tested code:

@IBAction func testPress(_ sender: Any) {
    let privatedatabase = CKContainer.default().privateCloudDatabase
    let newZoneName = UUID().uuidString
    let recordZone = CKRecordZone(zoneName: "ShareZone")

    privatedatabase.save(recordZone) {  savedRecordZone, error in

        if let error = error {
            print("\(error.localizedDescription).")
        } else if let savedRecordZone = savedRecordZone {
            print("\(error.localizedDescription).")

            let rootRecord = CKRecord(recordType: "RootRecord", zoneID: savedRecordZone.zoneID)
            rootRecord["Name"] = "Test" as CKRecordValue?

            privatedatabase.save(rootRecord) { record, error in
                if let error = error {
                    print("\(error.localizedDescription).")
                } else if let record = record {
                    print("successfully added rootRecord to cloud.")
                    self.shareTest( rootRecord: record)
                }
            }
        }
    }
}

func shareTest(rootRecord:CKRecord) {

    let ckContainer = CKContainer.default()
    let shareRecord = CKShare(rootRecord: rootRecord)

    let sharingController =  UICloudSharingController { controller, preparationCompletionHandler in

        let share = CKShare(rootRecord: record)
        share[CKShareTitleKey] = "Share Title" as CKRecordValue
        share.publicPermission = .none

        let modifyRecordsOperation = CKModifyRecordsOperation( recordsToSave: [rootRecord, share], recordIDsToDelete: nil)
        modifyRecordsOperation.timeoutIntervalForRequest = 10
        modifyRecordsOperation.timeoutIntervalForResource = 10

        modifyRecordsOperation.modifyRecordsCompletionBlock = { records, recordIDs, error in

            if let error = error {
                print(error.localizedDescription)
            }
            if let records = records {
                print("Share and Root records saved successfully")
            }
            preparationCompletionHandler(share, CKContainer(identifier: ckContainerID ), error)
        }

        myCloudDatabase.add(modifyRecordsOperation)
    }
    if let sharingController = sharingController {
        sharingController.availablePermissions = [.allowReadOnly, .allowReadWrite, .allowPrivate]
        sharingController.popoverPresentationController?.sourceView = sender
        sharingController.delegate = self
        self.present(sharingController, animated: true)
    }
}

// MARK: UICloudSharingControllerDelegate
// --------------------------------------
func cloudSharingController(_ csc: UICloudSharingController, failedToSaveShareWithError error: Error) {
    print("Failed to share to cloud: \(error)")
}
func itemTitle(for csc: UICloudSharingController) -> String? {
    return "Please join rootRecord share."
}
func cloudSharingControllerDidStopSharing(_ csc: UICloudSharingController) {
    print("Cloudkit stopped sharing")
}
func cloudSharingControllerDidSaveShare(_ csc: UICloudSharingController) {
    print("Cloudkit started sharing rootRecord")
}
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

James H. Sterling

James H. Sterling

Environmental Science & Climate Journalist

James Sterling reports on renewable energy developments, climate policy, ecological conservation, and green tech innovations around the globe.

Share this article
Twitter Facebook Pinterest