在后台线程上为 NSFetchedResultsController 执行 fetch 是个好主意吗?
Posted
技术标签:
【中文标题】在后台线程上为 NSFetchedResultsController 执行 fetch 是个好主意吗?【英文标题】:Is performing fetch for NSFetchedResultsController on a background thread a good idea? 【发布时间】:2016-08-29 21:53:14 【问题描述】:当用户运行应用程序时,他首先必须登录。如果登录成功,则会触发一个名为 setUpSaving 的函数。在 setUpSaving 中,正如我在代码的注释部分中所写的那样,(“发生了一些 firebase 事情,抓取所有消息,并且对于每条消息,它一条一条地通过 createMessageWithText 并将消息插入到核心数据中,最终保存它。”
所以,我的问题就在这里。假设一个用户有 20 000 条消息与他正在发送消息的人相关联。当他转到 ChatLogController 时,必须为用户提供所有消息。我这样做的方法是使用 NSFetchedResultsController 执行 fetch 来加载保存在登录控制器中的所有消息。我的问题是所有这些都在主队列上,有时,这已经冻结了 UI 很长一段时间。我的 chatLogController 代码在下面(不是全部,只是 fetchedResultsController 部分和 collectionView),我想知道如何在后台队列上执行 fetch,但仍然更新主队列上的 collectionView。
func setUpSaving()
///////some firebase stuff happens, grabs all the messages, and for each message, one by one, it goes through createMessageWithText and inserts the message into core data,
somewhere along the line context.save() gets triggered saving the message.
private func createMessageWithText(text: String, friend: Friend, context: NSManagedObjectContext, date: NSDate, isSender: Bool = false, sentStatus: String, fromID: String) -> Mesages
let message = NSEntityDescription.insertNewObjectForEntityForName("Mesages", inManagedObjectContext: context) as! Mesages
message.user = friend
message.text = text
message.timestamp = date
message.isSender = isSender
message.fromID = fromID
message.status = sentStatus
return message
lazy var fetchedResultsControler: NSFetchedResultsController =
let fetchRequest = NSFetchRequest(entityName: "Mesages")
fetchRequest.fetchBatchSize = 20
fetchRequest.includesPendingChanges = false
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: true)]
fetchRequest.predicate = NSPredicate(format: "user.id = %@", self.friend!.id!)
let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: moc, sectionNameKeyPath: nil, cacheName: nil)
frc.delegate = self
return frc
()
override func viewDidLoad()
super.viewDidLoad()
NavigationItems()
revealStatus()
do
try fetchedResultsControler.performFetch()
catch let err
print(err)
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) ->
Int
if let count = fetchedResultsControler.sections?[0].numberOfObjects
return count
return 0
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! JSQMessagesCollectionViewCell
return cell
【问题讨论】:
【参考方案1】:不,您不应该获取将在后台线程上驱动 UI 的 FRC。
您的问题是登录后加载 20,000 个项目的想法。没有人可以或将在移动设备上查看该数量的消息。您可能希望在登录后获得 20 个以及总数,但仅此而已。
当用户查看消息时,您应该按需加载可能包含 20 到 100 条消息的页面。这样,您就不会使用用户没有要求您使用的资源,也不会花费任何处理时间。
搜索也应该由服务器完成。
【讨论】:
嗨 Wain,感谢您的回复。虽然“搜索应该由服务器完成”是什么意思。我没有提到任何搜索功能。虽然如果它是我想念的东西,我会很感激你的意见! 我猜你可能会说搜索是设备上本地有 20k 个项目的原因... 哦,那么,一切都从 firebase 中抓取并保存到核心数据中,不知道会出现什么问题。 没有充分的理由在移动设备上本地拥有 20k 个项目,除非该应用作为主要用例离线使用。以上是关于在后台线程上为 NSFetchedResultsController 执行 fetch 是个好主意吗?的主要内容,如果未能解决你的问题,请参考以下文章
JVM在什么基础上为任务分配线程?提供了一个我在这里试过的例子[复制]