1

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

由于苹果照片应用程序立即响应,并在点击时准备好所有照片,我想知道他们是如何做到的。

对此有最佳做法吗?

代码示例

//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 
} 
+0

最好的做法是展示一些代码。 iOS通常足够快,你不会感到延迟,除非你做一些腥意...... – luk2302

+0

我编辑我的问题,包括示例代码。 – matteok

+0

您是否将图像存储在核心数据中? – Mika

回答

1

的问题是,你正在使用CoreData保存您的照片和苹果不。虽然文件大小和文件库可以使用的总大小没有限制,但获取文件所需的时间会比在文件结构中打开文件夹所需的时间要长。随着您将图片添加到应用程序,这会变得更糟,因为查询将返回越来越多的数据。这是您的应用程序的大小以及每张添加的照片的增加量。而不是CoreData,你应该将图片存储在文件系统中(以及CoreData中的路径)或库中。

如果使用核心数据路径,可以使用多种工艺来加速从批量查询到查询计数以建立集合视图以及仅显示当前显示的单元格中的图像等内容。

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

+0

CoreData有一个选项“允许外部存储”,如果它大于1mb,它将在外部存储二进制数据。我应该寻找一种BinaryData从未存储在数据库中的解决方案吗? – matteok

+0

这就是我会做的。你为什么不使用照片库?这就是它的目的! – Mika

+0

因为这些照片是通过Rest api与其他数据(如我需要存储在本地数据库中的注释)进行同步的。除了照片不一定出现在相机胶卷 – matteok