swiftdatabasecloudkitckrecord

Why is CloudKit not allowing me to save any records to my default container's public database?


I have an array of CKRecords that I'm trying to save to the default Container's public database for the first time. I created a CKModifyRecordsOperation and attempted to add the operation to the public database. It was unsuccessful but I'm not getting any error messages. So I tried adding each method individually to the database, sans any CKOperation... also unsuccessful, also devoid of error messages. To be sure, I checked my CloudKit Dashboard; there's nothing there.

Below is the method in question. It's hooked up to a simple IBAction for a button in an NSWindow. You can ignore the nested loops where I'm creating the CKRecords from my model data. They seem to be working as expected. My error checking code is inside of the completion blocks for CKModifyRecordsOperation. Specifically, the modifyRecordsCompletionBlock is printing: "Saved 0 records into CloudKit."

    @IBAction func uploadDataToCloudKit(_ sender: NSButton) {
        // Get CloudKit container and Public Database
        let myContainer = CKContainer.default()
        let publicDB = myContainer.publicCloudDatabase

        // Create array of cloudkit records so we can save a batch
        var cloudRecords = [CKRecord]()

        let groups = PayCodes().groups

        // For each PayCode Group...
        for payCodeGroup in groups {
            // Create CKRecord and give it a type
            let payCodeGroupRecord = CKRecord(recordType: "payCodeData")

            // For each PayCode in the group...
            for payCode in payCodeGroup.payCodes {
                // Fill the new CKRecord with key/value pairs
                payCodeGroupRecord.setObject(payCodeGroup.title as NSString, forKey: "group")

                if let commercialID = payCode.id.commercial as NSString?, let residentialID = payCode.id.residential as NSString? {
                    payCodeGroupRecord.setObject(commercialID, forKey: "commercialID")
                    payCodeGroupRecord.setObject(residentialID, forKey: "residentialID")
                }

                payCodeGroupRecord.setObject(payCode.title as NSString, forKey: "title")

                if let description = payCode.description as NSString? {
                    payCodeGroupRecord.setObject(description, forKey: "description")
                }

                payCodeGroupRecord.setObject((payCode.includesTripCharge ? 1 : 0) as NSNumber, forKey: "includesTripCharge")
                payCodeGroupRecord.setObject((payCode.needsResolutionCode ? 1 : 0) as NSNumber, forKey: "needsResolutionCode")


                payCodeGroupRecord.setObject(payCode.pay.commercial as NSNumber, forKey: "commercialPay")
                payCodeGroupRecord.setObject(payCode.pay.residential as NSNumber, forKey: "residentialPay")

                // Save new CKRecord into the Array
                cloudRecords.append(payCodeGroupRecord)
            }
        }

        print("There are \(cloudRecords.count) records about to be saved...")
        // print(cloudRecords)
        // Create an operation to save the records
        let operation = CKModifyRecordsOperation(recordsToSave: cloudRecords, recordIDsToDelete: nil)

        operation.perRecordCompletionBlock = { savedRecord, error in
            guard error != nil else {
                print("There was an error: \(error!.localizedDescription)")
                return
            }

            print("Saved a record into CloudKit")
        }

        operation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
            guard error != nil else {
                print("There was an error: \(error!.localizedDescription)")
                return
            }

            guard let savedRecords = savedRecords else { return }
            print("Saved \(savedRecords.count) records into CloudKit")
        }

        // Run the operation
        publicDB.add(operation)
//        cloudRecords.forEach { record in
//            publicDB.save(record) { savedRecord, error in
//                guard error != nil else {
//                    print("There was an error: \(error!.localizedDescription)")
//                    return
//                }
//                
//                guard let savedRecord = savedRecord else { return }
//                print("Saved a record: \(savedRecord.allKeys())")
//            }
//        }
    }

Solution

  • Your problem with the duplicate records is your reuse of the CKRecord instance.

    Change:

    for payCodeGroup in groups {
        // Create CKRecord and give it a type
        let payCodeGroupRecord = CKRecord(recordType: "payCodeData")
    
        // For each PayCode in the group...
        for payCode in payCodeGroup.payCodes {
            // Fill the new CKRecord with key/value pairs
            payCodeGroupRecord.setObject(payCodeGroup.title as NSString, forKey: "group")
    

    to:

    for payCodeGroup in groups {
        // For each PayCode in the group...
        for payCode in payCodeGroup.payCodes {
            // Create CKRecord and give it a type
            let payCodeGroupRecord = CKRecord(recordType: "payCodeData")
    
            // Fill the new CKRecord with key/value pairs
            payCodeGroupRecord.setObject(payCodeGroup.title as NSString, forKey: "group")