热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何在创建新记录时使用CloudKit在没有延迟的情况下更新TableView中的数据

如何解决《如何在创建新记录时使用CloudKit在没有延迟的情况下更新TableView中的数据》经验,为你挑选了1个好方法。

我的应用程序中有2个视图控制器.

第一个"MainViewController"显示一个tableView,其中包含从私有CloudKit数据库获取的CKRecords字段.在此VC的viewWillAppear方法中,我从CloudKit获取记录并重新加载tableview的数据,以显示先前由用户保存在CloudKit中的最新获取结果.

第二个视图控制器"CreateRecordViewController"用于创建CKRecords并将它们保存到CloudKit的私有数据库.

所以我在CreateRecordViewController中创建记录并在MainViewController中显示它们.

问题如下:当我在CreateRecordViewController创建记录时,它在CloudKit服务器上保存,但在关闭此CreateRecordViewController并转到MainViewController之后,tableview并不总是及时更新.

这是我的CreateRecordViewController中保存记录的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CloudKitManager.sharedInstance.privateDatabase.save(myRecord) { (savedRecord, error) -> Void in
 
           if error == nil {
 
 
       print("successfully saved record code: \(savedRecord)")
 
 
           }
           else {
               // Insert error handling
               print("error Saving Data to iCloud: \(error.debugDescription)")
           }
       }

记录保存后,关闭CreateRecordViewController并查看MainViewController.

正如我之前在MainViewController的viewWillAppear中所述,我检查iCloud是否可用,如果它可用,我从CloudKit获取所有记录并在tableView中显示它们.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
override func viewWillAppear(_ animated: Bool) {
 
       CKContainer.default().accountStatus { (accountStatus, error) in
           switch accountStatus {
           case .noAccount:  print("CloudKitManager: no iCloud Alert")
           case .available:
               print("CloudKitManager: checkAccountStatus : iCloud Available")
 
                self.loadRecordsFromiCloud()
 
           case .restricted:
               print("CloudKitManager: checkAccountStatus : iCloud restricted")
           case .couldNotDetermine:
               print("CloudKitManager: checkAccountStatus : Unable to determine iCloud status")
           }
       }
 
 
   }

在loadRecordsFromiCloud()中,当查询成功显示最新结果时,我也重新加载tableview异步.

我的MainViewController中的loadRecordsFromiCloud方法如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func loadRecordsFromiCloud() {
 
        // Get a private Database
        let privateDatabase = CloudKitManager.sharedInstance.privateDatabase
        let predicate = NSPredicate(value: true)
        let query = CKQuery(recordType: "MyRecords", predicate: predicate)
 
        let operation = CKQueryOperation(query: query)
 
 
        privateDatabase.perform(query, inZoneWith: nil) { (results, error) in
            if ((error) != nil) {
                // Error handling for failed fetch from public database
                print("error loading : \(error)")
 
            }
            else {
                // Display the fetched records
                //print(results!)
                self.tableViewDataArray = results!
 
                DispatchQueue.main.async {
                    print("DispatchQueue.main.sync")
                     self.tableView.reloadData()
                }
 
            }
        }
 
    }

有时当CloudKit服务器工作得更快时,我可以在tableView中看到新记录,但大多数时候都有延迟(我在MainViewController加载时没有在tableview中看到新结果)我认为这是因为我取记录它取出旧数据(不知道为什么),但也许我犯了另一个错误.这是一个糟糕的用户体验,我想知道如何避免这种延迟.我希望我的tableView在关闭CreateRecordViewController之后显示更新的结果.

我的第一个想法是订阅CloudKit Records更改,并在收到通知时在tableView中获取和重新加载数据,但我真的不需要推送通知(我宁愿在代码中只有一个方法,我可以从中获取数据CloudKit之后我知道所有CloudKit记录都已保存,或者在我知道创建了新记录之后,在获取并获取tableView数据之后我将调用tableView.reloadData,但我不确定如何实现这个权利(用什么方法)并不确定这是否是最好的解决方案.我也听说过在WWDC 2016专用于CloudKit的视频中,现在有一些与订阅Record更改相关的新方法,也许其中一些方法可以帮助(不确定).寻找最佳,或任何好的和简单的解决方案来解决这个问题(延迟问题).

我正在使用XCode 8,iOS 10,swift 3



1> agibson007..:

无法保证记录何时可用于查询,但您可以执行某些操作.您可以重新打印新记录.因为当您创建并保存记录时,您可以创建记录ID,您可以进行ckfetchrecordsoperation并从新记录中传递ID,并保证立即将其恢复.索引有时可能需要一段时间,这对CloudKit来说是令人沮丧的.因此,基本上保证快速数据库的最佳方法是进行查询,如果新记录ID不在那里,则使用id进行提取并将其附加到结果中.希望这是有道理的.

我之前必须这样做,因为我对CK并不太热衷.以下是将记录缝合回来的操作的链接.https://developer.apple.com/reference/cloudkit/ckfetchrecordsoperation如果您正在使用图像,请查看我创建的这个库,它允许您排除图像数据键并按需下载和缓存,可以加快您的查询速度.https://github.com/agibson73/AGCKImage

评论后编辑:

我认为你没有得到的部分是由于索引的工作方式,记录可能会或可能不会在viewcontroller 1中查询.你甚至在你的问题中提到它获取旧数据.这是由于服务器索引.如果删除记录,也会发生同样的情况.它仍然可以在查询中显示一段时间.在这种情况下,您将跟踪最近删除的记录ID,并在查询后将其删除.再次,我正在谈论的手动添加和删除是保证用户看到的内容的唯一方法,并且查询的结果与用户期望的内容保持同步.

这里有一些代码虽然完全未经测试,但我希望能帮助您想象我上面所说的内容.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
   func loadRecordsFromiCloud() {
 
    // Get a private Database
    let privateDatabase = CKContainer.default().privateCloudDatabase
    let predicate = NSPredicate(value: true)
    let query = CKQuery(recordType: "MyRecords", predicate: predicate)
 
    privateDatabase.perform(query, inZoneWith: nil) { (results, error) in
        if ((error) != nil) {
            // Error handling for failed fetch from public database
            print("error loading : \(error)")
 
        }
        else {
            //check for a newRecord ID that might be missing from viewcontroller 2 that was passed back
            if self.passedBackNewRecordID != nil{
                let newResults = results?.filter({$0.recordID == self.passedBackNewRecordID})
                //only excute if there is a new record that is missing from the query
                if newResults?.count == 0{
                    //houston there is a problem
                    let additiOnalOperation= CKFetchRecordsOperation(recordIDs: [self.passedBackNewRecordID!])
                    additionalOperation.fetchRecordsCompletiOnBlock= { recordsDict,fetchError in
                        if let newRecords = recordsDict?.values as? [CKRecord]{
                            //stitch the missing record back in
                            let final = newRecords.flatMap({$0}) + results!.flatMap({$0})
                            self.reloadWithResults(results: final)
                            self.passedBackNewRecordID = nil
 
                        }else{
                            self.reloadWithResults(results: results)
                            self.passedBackNewRecordID = nil
                        }
 
                    }
                    privateDatabase.add(additionalOperation)
                 }else{
                    //the new record is already in the query result
                    self.reloadWithResults(results: results)
                    self.passedBackNewRecordID = nil
                }
            }else{
                //no new records missing to do additional check on
                self.reloadWithResults(results: results)
            }
 
        }
    }
}
 
 
func reloadWithResults(results:[CKRecord]?){
       self.tableViewDataArray = results!
        DispatchQueue.main.async {
            print("DispatchQueue.main.sync")
             self.tableView.reloadData()
        }
 
    }
}

这有点乱,但你可以看到我拼错了缺少的recordID,如果不是nil回到你正在做的查询,因为该查询不能实时保证给你预期的新记录.在这种情况下,self.passedBackNewRecordID是根据Viewcontroller 2中的新recordID设置的.你如何设置或跟踪这个变量取决于你,但你可能需要一个完整的队列系统,因为我告诉你的是对记录的更改如何应用以及删除.因此,在生产应用程序中,我必须跟踪具有更改,删除和添加的记录,并获取每个记录的新版本,以便您可以想象对象列表的复杂性.由于我停止使用CloudKit,因为逻辑删除或索引花费的时间太长而无法显示查询中的更改.

测试保存的代码可能如下所示.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CloudKitManager.sharedInstance.privateDatabase.save(myRecord) { (savedRecord, error) -> Void in
 
           if error == nil {
 
 
       print("successfully saved record code: \(savedRecord)")
       //save temporarily to defaults
       let recordID = "someID"
       UserDefaults.standard.set(recordID, forKey: "recentlySaved")
       UserDefaults.standard.synchronize()
       //now we can dismiss
 
 
           }
           else {
               // Insert error handling
               print("error Saving Data to iCloud: \(error.debugDescription)")
           }
       }

在您在视图控制器1中调用查询的代码可能是viewWillAppear,您可以调用它

1
2
3
4
5
6
7
8
9
10
11
func startQuery(){
    UserDefaults.standard.synchronize()
    if let savedID = UserDefaults.standard.value(forKey: "recentlySaved") as? String{
        passedBackNewRecordID = CKRecordID(recordName: savedID)
        //now we can remove from Userdefualts
        UserDefaults.standard.removeObject(forKey: "recentlySaved")
        UserDefaults.standard.synchronize()
    }
 
    self.loadRecordsFromiCloud()
}

这应该非常贴合您的示例,并允许您测试我所说的内容,可能只进行微小的更改.


推荐阅读
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • Windows服务与数据库交互问题解析
    本文探讨了在Windows 10(64位)环境下开发的Windows服务,旨在定期向本地MS SQL Server (v.11)插入记录。尽管服务已成功安装并运行,但记录并未正确插入。我们将详细分析可能的原因及解决方案。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 本文介绍了在Windows环境下使用pydoc工具的方法,并详细解释了如何通过命令行和浏览器查看Python内置函数的文档。此外,还提供了关于raw_input和open函数的具体用法和功能说明。 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
author-avatar
一枝红杏出墙来2001
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有