Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/96.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用照片框架的视频采集器_Ios_Swift_Photosframework - Fatal编程技术网

Ios 使用照片框架的视频采集器

Ios 使用照片框架的视频采集器,ios,swift,photosframework,Ios,Swift,Photosframework,我正在尝试使用Photos框架提取用户库中的所有视频,并将它们显示在集合视图中。基本上实现了我自己的视频采集器 我正在使用PHCachingImageManager开始缓存每个视频的图像缩略图。当调用'cellForItemAt indexPath'时,当调用phcachingiManager.requestImage(…)并尝试在闭包中设置单元格的映像时,我会得到'Unexpective found nil When unwrapping a Optional value' viewDidLo

我正在尝试使用Photos框架提取用户库中的所有视频,并将它们显示在集合视图中。基本上实现了我自己的视频采集器

我正在使用PHCachingImageManager开始缓存每个视频的图像缩略图。当调用'cellForItemAt indexPath'时,当调用phcachingiManager.requestImage(…)并尝试在闭包中设置单元格的映像时,我会得到'Unexpective found nil When unwrapping a Optional value'

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
}
这可能是我实现PhotoCell类的方式的问题吗?或者我如何使用“collectionView.dequeueReusableCell(…)”的问题

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

出于某种原因,请删除以下行:

// Register Cell classes
self.collectionView!.register(PhotosCell.self, forCellWithReuseIdentifier: reuseIdentifier)
在ViewDidLoad()方法中,它可以很好地显示缩略图。在此之前,单元格没有初始化(我假设),并且在尝试设置单元格的UIImageView.image时抛出了错误


不确定这是否会影响UICollectionView的任何其他功能,但是…

出于某种原因,删除以下行:

// Register Cell classes
self.collectionView!.register(PhotosCell.self, forCellWithReuseIdentifier: reuseIdentifier)
在ViewDidLoad()方法中,它可以很好地显示缩略图。在此之前,单元格没有初始化(我假设),并且在尝试设置单元格的UIImageView.image时抛出了错误


不确定这是否会影响UICollectionView的任何其他功能,但是…

因为您的自我回答在不确定原因的情况下修复了该问题,这里有一个更全面的解释

当您在故事板中设置原型单元时,它会自动将该单元定义注册到集合视图中,因此您无需调用
registerCellClass
registernb

事实上,如果您确实调用了
registerCellClass
dequeueReusableCell
将尝试使用您的单元类的默认初始值设定项创建新的单元实例(
init(frame:)
)。这意味着它不会从故事板加载你的单元格类,因此你在那里设置的任何
IBOutlet
连接都不会被连接-因此你的单元格的
photo缩略图
outlet为零,导致你发现的陷阱

因此,您的自我回答是正确的-只是不要调用
registerCellClass
,让故事板为您处理它。(在幕后,Xcode将情节提要编译成多个nib,nib加载代码调用
registerNib:forCellWithReuseIdentifier:
,其中一个设置为原型单元。)


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

如果你看一下苹果的示例代码,他们会做一些额外的工作来确保单元格上图像的异步设置正确。在其
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
}

既然你自己的答案解决了这个问题,而你不知道为什么,这里有一个更全面的解释

当您在故事板中设置原型单元时,它会自动将该单元定义注册到集合视图中,因此您无需调用
registerCellClass
registernb

事实上,如果您确实调用了
registerCellClass
dequeueReusableCell
将尝试使用您的单元类的默认初始值设定项创建新的单元实例(
init(frame:)
)。这意味着它不会从故事板加载你的单元格类,因此你在那里设置的任何
IBOutlet
连接都不会被连接-因此你的单元格的
photo缩略图
outlet为零,导致你发现的陷阱

因此,您的自我回答是正确的-只是不要调用
registerCellClass
,让故事板为您处理它。(在幕后,Xcode将情节提要编译成多个nib,nib加载代码调用
registerNib:forCellWithReuseIdentifier:
,其中一个设置为原型单元。)


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

如果你看一下苹果的示例代码,他们会做一些额外的工作来确保单元格上图像的异步设置正确。在其
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
}

那么,
self.collectionView!。寄存器(photocell.self,forCellWithReuseIdentifier:reuseIdentifier)
mean?这意味着,“不要从故事板中的原型单元获取此单元。”但您确实希望从故事板中的原型单元获取此单元。显然,这样说是不对的。那么,
self.collectionView!是什么意思呢!。寄存器(photocell.self,forCellWithReuseIdentifier:reuseIdentifier)
mean?这意味着,“不要从故事板中的原型单元获取此单元。”但您确实希望从故事板中的原型单元获取此单元。显然,这样说是错误的。那么“registerCellClass”只在集合视图中设置单元格时使用?还有,这一行没有包含在表视图中的锅炉板代码中的原因吗?这看起来很奇怪,它包含在集合视图中,而不是表中。谢谢你给我上的课