2016-07-06 96 views
4

比方说,我有一个CKRecordrecordType后。发布后会保留一些值,如标题和说明。当应用程序中显示帖子时,会附上写它的用户的姓名和个人资料图片(我们称他们为Writer)。我的问题是 - 将CKReference存储到Writer的配置文件(配置文件是保存Writer详细信息的另一种类型的记录)最好吗?还是在写作时直接将作者的详细信息添加到Post中?使用CKReference与CKRecord的CloudKit性能

从数据库模式的角度来看,第一个选项非常有意义,但从性能角度来看,它似乎非常糟糕。在这个系统中有成千上万的用户,提取数量和加载时间似乎都不合理。

第一部分涉及加载所有帖子。

func loadPosts() { 
    // ...Setup the query 
    publicData.performQuery(query, inZoneWithID: nil) { (results: [CKRecord]?, error: NSError?) in 
     if let posts = results { 
      self.loadProfiles(posts) 
     } 
    } 
} 

一个查询完成,现在我们叫loadProfiles

func loadProfiles(posts: [CKRecord]) { 
    // Get the reference IDs out of the Posts 
    var referenceIDs = [CKRecordID]() 
    for post in posts { 
     // Get the reference from the post 
     // Append the recordID to the referenceIDs array 
    } 

    // Perform the Profiles fetch 
    let fetchOperation = CKFetchRecordsOperation(recordIDs: referenceIDs) 
    fetchOperation.fetchRecordsCompletionBlock = { records, error in 
     // ...Handle the fetched Profiles 

     // Everything has been fetched, update the UI now 
     dispatch_async(dispatch_get_main_queue(), { 
      self.tableView.reloadData() 
     }) 
    } 
    CKContainer.defaultContainer().publicCloudDatabase.addOperation(fetchOperation) 
} 

在该函数中,我们花费的时间抓住referenceIDs。然后,我们花时间进行配置文件提取。请注意,所有这些都是在原始的Post取回之后发生的!

...是的。即使有某种缓存系统,原始的抓取也会很疯狂(特别是对于很多用户)。

那么,在他们写作时直接将写作者的细节添加到帖子中会更好吗?优点:更少的抓取,更快的加载速度。缺点:如果编写者改变他们的个人资料的详细信息,应用程序将不得不遍历他们的所有帖子,并手动更新细节。

这整个两难困境挑选你的毒药情景。有一个更好的方法吗?

+0

我绝对建议参考,据我记录的表现。创建某种类型的本地缓存系统,然后在它的版本与您自己的版本不同时更新每个数据并更新它,可能是通过订阅通知。也就是说,这可能不是这个问题的最佳论坛,你可能在programmers.stackexchange.com或苹果开发论坛上运气更好。 –

+0

@thefredelement核心数据与某种通知来更新持久存储是有道理的。但是,原始的抓取仍然很长。我选择了StackOverflow而不是程序员,因为我有代码级别的实现。我希望有一个更好的方法来重构这个,而不必彻底改变广泛的结构。 –

+0

查看CloudKit订阅,您可以将一些订阅与核心数据组合在一起,并使用提取的结果控制器来处理一个很好的解决方案。你甚至可以用后台更新一些数据。 –

回答

5

您所描述的折衷术语是denormalization。这是你描述的困境。权衡权衡取决于底层技术以及应用领域和预期行为。

您已经描述了两个模型对象,一个帖子和一个配置文件,其中有一个作者对帖子上的配置文件的引用。你没有描述它们是如何被使用的,但是我将假设它是滚动的文章列表,在表格视图中,列表中的每个单元格上都有作者姓名和个人资料图片。这很明显,你为什么要关心每个人的引用。

CloudKit的优先事项是尽量减少往返服务器的次数。然而,一个获取帖子和另一个获取链接配置文件名称并不是特别繁重。 非常重要:使用desiredKeys属性获取和查询在这里,当你可以。 CloudKit默认获取整个记录,并且您可能会通过网络传递无关信息 - 这是获取用户名和获取用户完整配置文件的区别。

尽可能使用desiredKeys的要点在文档中没有足够的重要性,因为它对优化的重要性以及实现的简单性。

但是,如果您担心在提交帖子时发生响应,例如,如果用户在您拉动更多时等待,您可能需要进行非规范化处理。

我也将假设一个配置文件不会经常更改 - 这是一个关键重点 - 但它可以改变,应用程序需要考虑这一点。这其实很简单:在帖子中循环更新它们并不理想,但这不是什么大不了的事情,因为这是一个一次性的事情,你不希望经常发生。你应该可以用一对CKQueryOperation/CKModifyRecordsOperation来完成它。

再一次,一定要使用desiredKeys - 特别是如果你只是提取更新每个帖子上的非规范化字段,并不打算显示它的任何一个,你不想传递全部内容电线上的每一篇文章。

请注意,如果您使用配置文件图片进行非规范化处理,您可能需要确保您使用的是相同的CKAsset,因此您可以构建缓存,并且不会无意中上下传送相同的图像并存储一堆倍。请参阅关于CKAsset和本地缓存如何工作的警告;显然,如果你希望它保证本地存储,你必须自己缓存它。

,这是一个好一点要注意的是,所有这些CloudKit数据类型特别是不应该被用作您的应用程序的模型对象,以及如何将与层相互作用会影响你做出任何选择。

CloudKit实际上很棒,但在我看来,这是非系统化的文档。今年我有幸去WWDC('16),并且能够与一些CloudKit工程师进行交流,这些信息来自一些CloudKit工程师。希望这可以帮助。

+0

啊,哎呀,感谢伟大的的想法!我已经为每次抓取使用'desiredKeys'。我想我应该看看CKSubscription&Core Data来作为更新通知和持久存储。 –

+0

@ShaanSingh CKSubscription也很棘手,Core Data是它自己的野兽。这些是应用程序设计的问题,并没有简单的答案。 如果这确实回答了有关困境(非规范化)的问题,那么您是否可以将答案标记为已接受,谢谢。 –

+1

我已经在使用核心数据NSManagedObjects来保存帖子,用户,一切。核心数据对任何其他本机iOS缓存系统都有明显的好处。这个答案确实有助于回答我有关非规范化的问题。谢谢。 –