iOS,如何处理 iCloudKit 事务的发布通知请求?

Posted

技术标签:

【中文标题】iOS,如何处理 iCloudKit 事务的发布通知请求?【英文标题】:iOS, How to handle post notification request(s) for iCloudKit Transactions? 【发布时间】:2017-02-26 22:29:48 【问题描述】:

首先,如果用户拒绝接受推送通知的请求,如何评估。

根据我的阅读,静默通知似乎存在问题,虽然我认为这是一个测试版,但这个问题是否已得到纠正。

我正在开发一个儿童应用程序,当我拨打registerForRemoteNotifications 捕获静默通知时,这会显示通知权限消息吗?

我还想知道如果用户不经常访问互联网,iCloud 数据库设置会发生什么。我的意思是我猜他们必须在首次下载应用程序时拥有,但如果他们在下载应用程序后从未运行过应用程序,他们将如何获得数据库架构?这是我们必须处理并要求用户连接到互联网的事情吗?

我知道其中很多是假设的,但显然我们需要捕捉并处理它。

如果有人能指出可能有帮助的有用 pod,我也将不胜感激。

【问题讨论】:

啊,我已经回答了我的一个问题,我看到这个错误已经修复了***.com/questions/31108576/… 【参考方案1】:

朱尔斯,

当您使用支持 iCloud 的应用程序创建记录时,您可以使用与此类似的一段代码。

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

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

        let theLinkID = CKReference(recordID: sharedDataAccess.iCloudID, action: .deleteSelf)
        let thePath = sharedDataAccess.fnGet(index2seek: rex)
        newRecord["theLink"] = theLinkID
        newRecord["theBLAHnumber"] = rex as CKRecordValue?
        newRecord["theBLAHpath"] = thePath 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 
            print("ok \(savedRecords)")
        
    

    saveRecordsOperation.qualityOfService = .background
    privateDB.add(saveRecordsOperation)
    theApp.isNetworkActivityIndicatorVisible = true

现在原谅我这里有很多,我没有时间详细解释,但是记录方案来自这段代码中的CKRecord创建调用第4行,记录类型称为“Blah”在这种情况下。

其中的字段 [架构],您需要像我在这里所做的那样在代码中详细说明,因此在这种情况下,我们有链接、BLAH 编号和 BLAH 路径。它不会下载这些信息,而且实际上一旦投入生产,就无法更改它。因此,新模式需要是新的记录类型,并且您需要注意对当前模式的字段更新,以确保您的应用程序是落后的。兼容的。希望这有助于让事情变得更清晰。

这篇文章https://www.shinobicontrols.com/blog/ios8-day-by-day-day-33-cloudkit 更详细地讨论了整个主题。原子提交,这里特别提到了你的一个问题。

【讨论】:

非常感谢您的回答,我看到您对各种事情的错误处理,太好了。 iCloudKit 框架是否为我们处理本地存储(我目前有一个 SqlLite 数据库),说没有网络访问并且无法提交记录? 本地存储,不确定我是否理解您的问题。虽然我认为答案是否定的。你当然可以使用 Core Data 之类的东西,它会以某种方式在框架内处理本地存储。当然,您也可以在 iCloud 框架中使用 SQL 类型查询,所以这可能至少部分回答了您的问题。 我的意思是,我可以仅依赖 iCloud 数据库功能,还是需要缓存数据并保留可能尚未提交给 iCloud 的任何事务? Jules 我已经编辑了我的答案并包含了一个链接来帮助您解决最后一条评论。我认为寻找的关键词是原子提交,CloudKit 支持的东西,但与以往一样有一些限制。

以上是关于iOS,如何处理 iCloudKit 事务的发布通知请求?的主要内容,如果未能解决你的问题,请参考以下文章

Npgsql 如何处理失败的事务?

您通常如何处理数据库事务日志?

清洁架构 - 如何处理数据库事务?

如何处理 jdbc 事务中的父键约束?

如何处理 Spring 集成流的事务(Java DSL)

如何处理SQL Server事务复制中的大事务操作