ios - 使用照片框架的视频选择器

标签 ios swift photosframework

我正在尝试使用照片框架提取用户库中的所有视频,并将它们显示在 Collection View 中。基本上是实现我自己的视频选择器。

我正在使用 PHCachingImageManager 开始缓存每个视频的图像缩略图。当“cellForItemAt indexPath”被调用时,当我调用 PHCachingImageManager.requestImage(...) 并尝试在闭包中设置我的单元格图像时,我得到“在展开可选值时意外发现 nil”。

viewDidLoad() {
    // Register Cell classes
    self.collectionView!.register(PhotosCell.self, forCellWithReuseIdentifier: reuseIdentifier)

    let videosAlbum = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .smartAlbumVideos, options: nil)

    print(videosAlbum.count) // prints as 1 bc videosAlbum contains 1 collection
    self.videos = PHAsset.fetchAssets(in: videosAlbum.object(at: 0), options: nil)
    print(self.videos.count) // prints the # of videos in the Videos smart album

    self.imageManager.startCachingImages(for: self.videos.objects(at: [0, videos.count-1]), targetSize: CGSize(width: 150, height: 150), contentMode: .aspectFit, options: nil)
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! PhotosCell
    let asset = videos.object(at: indexPath.item)

    imageManager.requestImage(for: asset, targetSize: CGSize(width: 150, height: 150), contentMode: .aspectFill, options: nil, resultHandler: {
        image, _ in
                cell.thumbnailImage = image //this is the line throwing the error
    })
    return cell
}

这可能是我实现 PhotosCell 类的方式有问题吗?还是我使用“collectionView.dequeueReusableCell(...)”的方式有问题?

class PhotosCell: UICollectionViewCell {

@IBOutlet weak var photoThumbnail: UIImageView!

var thumbnailImage: UIImage! {
    didSet {
        photoThumbnail.image = thumbnailImage
    }
}
}

我环顾四周,认为我看到传递给缓存管理器的闭包放在后台线程上的位置,但这不应该影响可选的 UIImageView.image 被设置在错误的行上,对吧? GitHub 代码为 here了解更多上下文。

最佳答案

由于您的 self 回答在不确定原因的情况下解决了问题,因此这里有一个更完整的解释...

当您在 Storyboard 中设置原型(prototype)单元格时,它会自动将该单元格定义注册到 Collection View 中,因此您无需调用 registerCellClassregisterNib

事实上,如果您确实调用registerCellClassdequeueReusableCell 将尝试使用您的单元类的默认初始化程序(init(frame:) 最有可能)。这意味着它不会从 Storyboard 中加载您的单元格类,因此您在那里设置的任何 IBOutlet 连接都不会连接 — 因此您的单元格的 photoThumbnail socket 为 nil,造成你发现的陷阱。

所以您的 self 回答是正确的 — 只是不要调用 registerCellClass 并让 Storyboard为您处理。 (在幕后,Xcode 将您的 Storyboard编译成多个 nib,并且 nib 加载代码调用 registerNib:forCellWithReuseIdentifier: 并将您设置为原型(prototype)单元格的那个。)


既然我们在这里,让我们修复您的代码中的另一个可能的问题。您的 requestImage 完成处理程序直到 collectionView(_:cellForItemAt:) 返回后才会执行。这意味着在滚动期间或之后,您设置图像的单元格可能已被重复使用 — 因此它现在代表一个与您为其请求图像的单元格不同的 indexPath,并且您现在在其上设置了错误的图像。

如果您查看 Apple 的 Using Photos Framework示例代码,他们做了一些额外的工作来确保单元格上图像的异步设置正确运行。在他们的 AssetGridViewController 中:

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let asset = fetchResult.object(at: indexPath.item)

    // Dequeue a GridViewCell.
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: GridViewCell.self), for: indexPath) as? GridViewCell
        else { fatalError("unexpected cell in collection view") }

    // Request an image for the asset from the PHCachingImageManager.
    cell.representedAssetIdentifier = asset.localIdentifier
    imageManager.requestImage(for: asset, targetSize: thumbnailSize, contentMode: .aspectFill, options: nil, resultHandler: { image, _ in
        // The cell may have been recycled by the time this handler gets called;
        // set the cell's thumbnail image only if it's still showing the same asset.
        if cell.representedAssetIdentifier == asset.localIdentifier {
            cell.thumbnailImage = image
        }
    })
    return cell
}

关于ios - 使用照片框架的视频选择器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40383838/

相关文章:

ios - 使用 Xcode 11.2 在 iOS 模拟器中打开 .app 时出错

ios - 从 Swift 4 的文件目录中删除用户选择的文件?

ios - Swift 中的照片框架升序

swift - 尝试从 PHAssetCollection.fetchAssetCollections 获取所有照片时出错

ios - 如何使用照片框架获取引用网址的文件名?

ios - 如何解除分配 id<MTLBuffer> Metal iOS?

iphone - 如何在 Xcode 中显示/隐藏 View

iphone - 调试 iPhone 应用程序

Swift Cocoa - Process() 不允许 sudo

swift - 具有圆形边缘的自定义表格 View 单元格