Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CloudKit - full and complete error handling example

Apple are very clear, in every video they state that "The difference between a CloudKit app which handles errors and one that doesn't is the difference between a working app and one that doesn't". However, I can't find anywhere a proper list of what each error means, which Operations throw what or any example code of CloudKit error handling done well for various CKOperations. Even worse, many examples don't handle errors at all and I can't find any documentation from Apple either.

Does anyone have a full and complete example they can share? Any lists of which Operations can throw what?

This post shows a list of errors and a short description of each error. I created this new post because I'm specifically looking for full and complete examples of error handling as Apple recommends. The other post has an incomplete example and is asking specific questions. I already highlighted this post in the comments because it contains a short description of each error type which is useful.

like image 879
robwithhair Avatar asked May 17 '17 11:05

robwithhair


1 Answers

Rob,

Here 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's 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
}
like image 130
user3069232 Avatar answered Oct 20 '22 19:10

user3069232