我正在使用NSFetchedResultsController在聊天室应用中显示消息。
在appDelegate中分配上下文变量,并在聊天室中使用该上下文的引用。
let context = persistentContainer.viewContext
我在viewDidLoad中按如下方式初始化NSFRC:
func initializeResultsController() {
let request = NSFetchRequest<Message>(entityName: "Message")
let messageSort = NSSortDescriptor(key: "dateCreated", ascending: true)
request.sortDescriptors = [messageSort]
request.predicate = NSPredicate(format: "chatRoomId == %@", self.chatRoomId)
request.fetchBatchSize = 30
fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: "messageDateSectionIdentifier", cacheName: self.chatRoomId)
fetchedResultsController.delegate = self
do {
try fetchedResultsController.performFetch()
} catch {
fatalError("Failed to initialize FetchedResultsController: \(error)")
}
}
sectionNameKeyPath(&#34; messageDateSectionIdentifier&#34;)是派生属性,因此可以将这些部分划分为日历日。
我有两个问题。首先,batchSize似乎被忽略,其次缓存似乎对性能没有影响。消息越多,选择聊天室时的延迟时间越长。 1500条消息约1秒钟。
当我编辑scheme以在控制台中显示coreData信息时,在第一次出现视图时多次执行30行的批处理请求,在一种情况下,阵列大小为1500.不确定是故障数组还是填充的阵列。控制台printOut是:
CoreData: annotation: sql connection fetch time: 0.0013s
CoreData: annotation: total fetch execution time: 0.0014s for 1454 rows.
CoreData: annotation: Bound intarray _Z_intarray0
CoreData: annotation: Bound intarray values.
此次重复多次,值为30行。
我已经尝试将sectionNameKeyPath简化为dateCreated,以查看派生的部分是否存在问题,但根本没有区别。我还应该提到,与所有聊天应用程序一样,应用程序最初会在呈现时滚动到底部。
我想要的是缓存工作以及fetchBatchSize工作,以便最初从coreData获取只有30行,直到用户开始向上滚动。现在由此方法引起的延迟对我的应用程序性能产生了可测量的影响。
答案 0 :(得分:1)
batchSize
不尊重fetchedResultsController
,这是正确的。 NSFetchedResultsController执行提取,然后跟踪上下文中的所有更改,以查看是否添加,删除,移动或更改了任何内容。如果它仅通过遵循batchSize来获取匹配实体的子集,则它将无法完成它的工作。
您可以通过将谓词设置为仅在特定日期之后获取消息来解决此问题。为了弄清楚截止日期是什么,你可以先进行一次提取,其中batchSize = 1,batchOffset = [你最初需要多少消息来自fetchedResultsController]。随着收集的更多信息将会超出您的初始限制。
另请注意,为集合中的EVERY元素调用sectionNameKeyPath。因此即使做少量工作也会造成巨大的延误。不要在sectionNameKeyPath中创建日历或dataFormatter - 重用一个。
答案 1 :(得分:0)
我终于找到了引起问题的原因。
如果您在tableView heightForRowAt中引用fetchedResultsController,则fetchBatchSize将循环遍历并在您指定的fetchBatchSize循环中加载所有数据。
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let item = self.fetchedResultsController!.object(at: indexPath)
// get and return height of item
return item.heightOfItem
}
如果您使用UITableViewAutomaticDimension或定义不需要引用fetchedResultsController的高度(即固定高度),则不会出现此问题,并且fetchBatchSize可以正常工作。
不幸的是,我发现UITableViewAutomaticDimension对于滚动性能不可接受,因此我想我必须使用偏移量手动配置批处理负载。
我还有一个额外的问题,该问题导致数据的循环加载。在我的情况下,那就是sectionNameKeyPath是一个过渡属性。这也引起了问题,但不幸的是有必要。
如果您在使用NSFetchedResultsController使用fetchBatchSize时遇到问题,我建议您看一下这两个问题。