NSFetchedResultsController 导致延迟 segue

NSFetchedResultsController causes delayed segue

我正在构建一个看起来类似于 iphone 上的 Apples Photos 应用程序的应用程序。使用 Master-Detail 界面,用户选择一个相册并被带到显示一堆照片的 UICollectionViewController。对于主视图控制器和详细视图控制器,我都使用 NSFetchedResultsControllers 从数据库访问对象。不幸的是,现在选择相册时有一个非常明显的延迟,这是由 NSFetchedResultsController 获取项目的细节引起的。

由于 apples photos 应用会立即响应并在单击时准备好所有照片,我想知道他们是如何做到的。

有这方面的最佳实践吗?

代码示例

//DetailViewController.swift

// lazy frc
var fetchedResultsController: NSFetchedResultsController {
    if _fetchedResultsController != nil {
        return _fetchedResultsController!
    }

    let fetchRequest = NSFetchRequest()
    // Edit the entity name as appropriate.
    let entity = NSEntityDescription.entityForName("Photo", inManagedObjectContext: self.context)
    fetchRequest.entity = entity

    // Set the batch size to a suitable number.
    fetchRequest.fetchBatchSize = 20

    // Edit the sort key as appropriate.
    let sortDescriptor = NSSortDescriptor(key: "photoID", ascending: false)
    let sortDescriptors = [sortDescriptor]

    fetchRequest.sortDescriptors = [sortDescriptor]

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    let aFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.context, sectionNameKeyPath: nil, cacheName: "ernesto")
    aFetchedResultsController.delegate = self
    _fetchedResultsController = aFetchedResultsController

    var error: NSError? = nil
    if !_fetchedResultsController!.performFetch(&error) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        //println("Unresolved error \(error), \(error.userInfo)")
        abort()
    }

    return _fetchedResultsController!
}
var _fetchedResultsController: NSFetchedResultsController? = nil


// MARK: - UICollectionViewDataSource
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! PhotoCell
    let item = self.fetchedResultsController.objectAtIndexPath(indexPath) as! NSManagedObject
    cell.backgroundColor = UIColor.yellowColor()
    //the following line is commented out intentionally to make sure the delay is not caused by setting the image
    //cell.imageView.image = UIImage(data: item.valueForKey("image") as! NSData)
    return cell
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    let sectionInfo = self.fetchedResultsController.sections![section] as! NSFetchedResultsSectionInfo
    return sectionInfo.numberOfObjects
}

func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
    return 1
}

问题是你使用CoreData来存储你的图片而apple没有。尽管文件大小和图书馆可以使用的总大小没有限制,但获取文件所需的时间比打开文件结构中的文件夹要长。当您将图片添加到应用程序时,情况会变得更糟,因为查询会 return 越来越多的数据。这不包括您的应用程序的大小,它会随着每张添加的照片而增加。您应该将图片存储在文件系统(以及 CoreData 中的路径)或库本身中,而不是 CoreData。

如果您使用核心数据路线,您可以使用多种技术来加速从批量查询到查询计数以构建集合视图以及仅当前显示的单元格中的图像的过程。

另一种方法是将每张照片以全分辨率存储两次,一次以小得多的尺寸存储。较小的是用户显示集合视图,集合和细节之间的动画,在前几微秒内,照片在全分辨率图片到达那里之前显示在细节视图中。