0

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())")
//            }
//        }
    }
Mikis
  • 80
  • 2
  • 7
  • Are you getting any of the print statements? – rmaddy Sep 11 '17 at 05:51
  • Have you verified access to the container using the `CKContainer accountStatus(completionHandler:)` method? – rmaddy Sep 11 '17 at 05:52
  • Yes, I have: it's available. On the other hand, I just realized why I wasn't getting any error messages. It's because I was being dumb with my guard statements... a negation error. Now that I've fixed it, though, it's giving me this error: `There was an error: You can't save the same record twice: `. But, there's no data saved in the database when I check via CloudKit Dashboard. Any idea what could be the problem? Thanks. – Mikis Sep 11 '17 at 06:06
  • Are you looking in the correct container in the Dashboard? – rmaddy Sep 11 '17 at 06:08
  • Yeah, I am. I just reset the development environment in that container as well. I assume that if there was anything in the public database, this action would have emptied it, right? Well, I tried to upload the data programmatically again... and it's still giving me the same error. – Mikis Sep 11 '17 at 06:12
  • @MikisWoodwinter did you find a solution to this? – Jules Nov 11 '18 at 11:07

1 Answers1

2

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")
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • Aw, man. That makes so much sense. Thank you! So... I fixed that... and the error I'm getting now says I have "an invalid BundleId for my container." Is there a specific format that your BundleID is supposed to be in? Like, reverse DNS notation or something? Thanks again, man. I'd accept your answer, if I could... but I only have 13 rep points :( – Mikis Sep 11 '17 at 06:24
  • You can accept the answer but you might have to wait a few minutes. Rep is not an issue for accepting an answer to your own question. As for the container issue, is your app setup to use the default container in Xcode? – rmaddy Sep 11 '17 at 06:26
  • Got it. It's accepted. And, yes; it's setup to use the default container. Should it not be? – Mikis Sep 11 '17 at 06:30
  • That should be fine. I wonder if it's a temporary issue. Another person posted about the same issue several hours ago: https://stackoverflow.com/questions/46144170/cloudkit-invalid-bundle-id-for-container – rmaddy Sep 11 '17 at 06:31
  • Hmm. It might be. I guess I'll just try again in a few hours and see what happens. Thanks again for your help, man. – Mikis Sep 11 '17 at 06:34