嵌套 CloudKit 查询和 UITableView

Posted

技术标签:

【中文标题】嵌套 CloudKit 查询和 UITableView【英文标题】:Nested CloudKit queries and UITableView 【发布时间】:2015-02-06 21:11:31 【问题描述】:

我正在尝试使用CloudKit 制作一个简单的基于表格的应用程序,它允许您深入查找有关特定项目的更多信息。假设我的应用显示了位于主题公园内的商店目录,按公园的各个部分划分。

在我的初始表格视图中,我能够获得 ThemeParks 的列表。点击 ThemePark 会向下钻取到另一个表视图,其中包含公园每个部分的部分标题。我能够查询具有与所选主题公园匹配的CKReference 的部分。当我尝试获取与每个部分匹配的商店时,就会出现问题。我不知道如何等到商店全部下载后才能重新加载表格视图。这是我的视图控制器的一些示例代码:

func getSectionsFromCloud() 
    let cloudContainer = CKContainer.defaultContainer()
    let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase
    let recordToMatch = CKReference(recordID: themePark.recordID, action: CKReferenceAction.DeleteSelf)
    let predicate = NSPredicate(format: "themeParkOwner == %@", recordToMatch)
    let query = CKQuery(recordType: "ThemeParkSection", predicate: predicate)
    let sort = NSSortDescriptor(key: "name", ascending: true)
    query.sortDescriptors = [sort]
    self.publicDatabase.performQuery(query, inZoneWithID: nil, completionHandler: 
        results, error in

        if error == nil 
            println("Successfully retrieved sections")
            self.sections = results as [CKRecord]
            for section in self.sections 
                self.getShopsFromCloud(section)
            

         else 
            println(error)
        
    )

这是我的getShopsFromCloud 函数:

func getShopsFromCloud(record:CKRecord) 
    let cloudContainer = CKContainer.defaultContainer()
    let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase
    let recordToMatch = CKReference(recordID: record.recordID, action:CKReferenceAction.DeleteSelf)
    let predicate = NSPredicate(format: "sectionOwner == %@", recordToMatch)
    let query = CKQuery(recordType: "Shop", predicate: predicate)
    self.publicDatabase.performQuery(query, inZoneWithID: nil, completionHandler: 
            results, error in

        if error == nil 
            println("Successfully retrieved shops.")
            self.shops.append(results as [CKRecord])

         else 
            println(error)
        
    )

问题是,getSectionsFromCloud() 在所有 getShopsFromCloud() 调用之前完成。因此,如果我在完成处理程序中为 getSectionsFromCloud 重新加载表视图,它将不会显示商店。但是,如果我在completionHandler 中为getShopsFromCloud 重新加载表视图,则每次执行查询时(每个部分执行一次),numberOfRowsInSection 也会为每个部分调用一次。所以如果我的numberOfRowsInSection是这样的:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

        return self.shops[section].count

...我收到“致命错误:数组索引超出范围”错误,因为第一个商店数组已下载,但随后为第二个数组调用 numberOfRowsInSection,但该数组尚不存在。那么我如何知道getShopsFromCloud() 何时结束以及我在世界上的哪个位置拨打tableView.reloadData() 电话?

【问题讨论】:

好吧,你需要看看 GCD - Using Dispatch Groups。 感谢您为我指明正确的方向! 查看本教程以了解其工作原理:raywenderlich.com/79150/…。在您的情况下,您需要创建一个将下载部分的调度组,然后在完成后,您将使用行更新部分并重新加载表视图。 【参考方案1】:

尝试使用获取请求之间的依赖关系,并将它们添加到数据库对象(CKContainer.defaultContainer().publicDatabase().addOperation)的队列中,而不是调用便捷方法

【讨论】:

对于像我这样的新手来说,这最终成为最容易理解的解决方案!谢谢。【参考方案2】:

我认为解决此问题的最简单方法是在创建 self.sections 数组的同时创建 self.shops 数组。只需确保每个 self.shops 项目还包含一个空数组。这样计数将返回 0,因为尚未获取列表。在 getShopsFromCloud 中执行 reloaddata 是正确的方法。您必须知道您需要在主队列上执行 reloaddata。

【讨论】:

以上是关于嵌套 CloudKit 查询和 UITableView的主要内容,如果未能解决你的问题,请参考以下文章

如何从 CloudKit 查询和获取数据?

Cloudkit 关于时间和标记的查询

CloudKit 查询中的 UITableView 部分

在 CloudKit 中使用比较谓词进行查询

为啥我不能从 Xcode 或 CloudKit Dashboard 查询 CloudKit?

CloudKit 数据库查询问题