CloudKit - 完整且完整的错误处理示例

Posted

技术标签:

【中文标题】CloudKit - 完整且完整的错误处理示例【英文标题】:CloudKit - full and complete error handling example 【发布时间】:2017-05-17 11:44:57 【问题描述】:

Apple 非常清楚,他们在每个视频中都声明“处理错误的 CloudKit 应用程序和不处理错误的应用程序之间的区别是工作应用程序和不处理错误的应用程序之间的区别”。但是,我无法在任何地方找到每个错误意味着什么的正确列表,哪些操作抛出了什么或 CloudKit 错误处理的任何示例代码对于各种 CKOOperation 都做得很好。更糟糕的是,许多示例根本不处理错误,我也找不到任何来自 Apple 的文档。

有没有人可以分享一个完整的例子? 哪些操作可以抛出什么列表?

This post 显示错误列表和每个错误的简短描述。我创建了这篇新文章,因为我专门寻找 Apple 推荐的完整和完整的错误处理示例。另一篇文章有​​一个不完整的例子,并提出了具体问题。我已经在 cmets 中突出显示了这篇文章,因为它包含对每个有用的错误类型的简短描述。

【问题讨论】:

我在这里找到了this post,其中包含每个错误的简短描述。 我创建了这篇新文章,因为我专门寻找 Apple 推荐的完整和完整的错误处理示例。您提到的帖子有一个不完整的示例,并且正在询问具体问题。我已经在上面突出显示了这篇文章,因为它包含对每种有用的错误类型的简短描述。 developer.apple.com/reference/cloudkit/ckerrorcode Rob,我现在自己也在同一条船上。我的基本 CloudKit 同步系统稳定且快速,我需要填写所有错误条件。在浏览 Apple CloudKit 代码示例时,我在“CloudKit Share”示例代码中遇到了他们的解决方案。我在想我会用它作为我的解决方案的基础......不确定它是否显示所有可能的错误,但它看起来是一个好的开始......developer.apple.com/library/content/samplecode/CloudKitShare/… 【参考方案1】:

罗伯,

这里是一个例子...

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

【讨论】:

谢谢!使用 NotificationCenter 向用户显示合适的响应真是个好主意。我正在考虑一个详尽的开关将确保所有错误都得到处理,并且将来添加错误会提供编译器错误以通知用户?然而,由于并非所有 CKOperations 都可以抛出所有 CKError 类型,这似乎很多错误都是不必要的。遗憾的是,没有列出哪些操作会引发哪些错误的列表。至少我还没有找到。 请注意,错误仅包含两种情况下的 CKErrorRetryAfterKey:serviceUnavailable 和 requestRateLimited(至少每个苹果文档:developer.apple.com/documentation/cloudkit/ckerrorretryafterkey)

以上是关于CloudKit - 完整且完整的错误处理示例的主要内容,如果未能解决你的问题,请参考以下文章

异常处理

JavaScript 错误处理完整指南

CloudKit 错误处理 - 重试逻辑

处理 CloudKit 错误和 CKError

Kapt 注释处理 - 如何显示完整的堆栈跟踪

拒绝千篇一律,这套Go错误处理的完整解决方案值得一看!