CloudKit - A Complete and Complete Error Handling Example

Apple is very clear, in every video it says that "the difference is between a cloud application that handles errors and that which is not the difference between a working application and one that does not work." However, I cannot find anywhere a proper list of what each error means that Operations generate any or any example of CloudKit error handling code that works well for various CKO operations. Even worse, many examples do not handle errors at all, and I also cannot find Apple's documentation.

Does anyone have a complete and complete example that they can share? Any lists from which Operations can drop what?

This post contains a list of errors and a brief description of each error. I created this new post because I'm specifically looking for a complete and complete example of error handling, as Apple recommends. In another post, there is an incomplete example and specific questions are asked. I already highlighted this post in the comments because it contains a brief description of each type of error, which is useful.

+4
source share
1 answer

Rob

Here is an example ...

func files_saveNotes(rex: Int) {
     var localChanges:[CKRecord] = []

        let newRecordID = CKRecordID(recordName: sharedDataAccess.returnRexID(index2seek: rex))
        let newRecord = CKRecord(recordType: "Note", recordID: newRecordID)

        let theLinkID = CKReference(recordID: sharedDataAccess.iCloudID, action: .deleteSelf)
        let thePath = sharedDataAccess.fnGet(index2seek: rex)
        newRecord["theLink"] = theLinkID
        newRecord["theNo"] = rex as CKRecordValue?
        newRecord["thePath"] = thePath as CKRecordValue?



        let miam = sharedDataAccess.fnGetText(index2seek: rex)
        let range = NSRange(location: 0, length: miam.length)
        let dataMiam = try? miam.data(from: range, documentAttributes: [NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType])

        newRecord["theRTF"] = dataMiam as? CKRecordValue


    localChanges.append(newRecord)
    let records2Erase:[CKRecordID] = []

    let saveRecordsOperation = CKModifyRecordsOperation(recordsToSave: localChanges, recordIDsToDelete: records2Erase)
    saveRecordsOperation.savePolicy = .allKeys
    saveRecordsOperation.perRecordCompletionBlock =  { record, error in
        if error != nil {
            //print(error!.localizedDescription)
        }
        // deal with conflicts
        // set completionHandler of wrapper operation if it the case
    }
    saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
        self.theApp.isNetworkActivityIndicatorVisible = false

        guard error == nil else {
            if let ckerror = error as? CKError {
                if ckerror.code == CKError.requestRateLimited {
                    let retryInterval = ckerror.userInfo[CKErrorRetryAfterKey] as? TimeInterval
                    DispatchQueue.main.async {
                        Timer.scheduledTimer(timeInterval: retryInterval!, target: self, selector: #selector(self.files_saveNotes), userInfo: nil, repeats: false)
                    }
                } else if ckerror.code == CKError.zoneBusy {
                    let retryInterval = ckerror.userInfo[CKErrorRetryAfterKey] as? TimeInterval
                    DispatchQueue.main.async {
                        Timer.scheduledTimer(timeInterval: retryInterval!, target: self, selector: #selector(self.files_saveNotes), userInfo: nil, repeats: false)
                    }
                } else if ckerror.code == CKError.limitExceeded {
                    let retryInterval = ckerror.userInfo[CKErrorRetryAfterKey] as? TimeInterval
                    DispatchQueue.main.async {
                        Timer.scheduledTimer(timeInterval: retryInterval!, target: self, selector: #selector(self.files_saveNotes), userInfo: nil, repeats: false)
                    }
                } else if ckerror.code == CKError.notAuthenticated {
                    NotificationCenter.default.post(name: Notification.Name("noCloud"), object: nil, userInfo: nil)
                } else if ckerror.code == CKError.networkFailure {
                    NotificationCenter.default.post(name: Notification.Name("networkFailure"), object: nil, userInfo: nil)
                } else if ckerror.code == CKError.networkUnavailable {
                    NotificationCenter.default.post(name: Notification.Name("noWiFi"), object: nil, userInfo: nil)
                } else if ckerror.code == CKError.quotaExceeded {
                    NotificationCenter.default.post(name: Notification.Name("quotaExceeded"), object: nil, userInfo: nil)
                } else if ckerror.code == CKError.partialFailure {
                    NotificationCenter.default.post(name: Notification.Name("partialFailure"), object: nil, userInfo: nil)
                } else if (ckerror.code == CKError.internalError || ckerror.code == CKError.serviceUnavailable) {
                    NotificationCenter.default.post(name: Notification.Name("serviceUnavailable"), object: nil, userInfo: nil)
                }
            } // end of guard statement
            return
        }
        if error != nil {
            //print(error!.localizedDescription)
        } else {
            //
        }
    }

    saveRecordsOperation.qualityOfService = .background
    privateDB.add(saveRecordsOperation)
    theApp.isNetworkActivityIndicatorVisible = true
}
+2
source

Source: https://habr.com/ru/post/1677348/


All Articles