我正在尝试构建一个视频合并应用,允许用户从集合视图中选择几个短片段,然后生成所有合并为一个视频的预览。我正在使用Photos框架(PHCachingImageManager)来填充集合视图,并将所选PHAssets的数组传递给下面的函数,以便请求低质量的AVAssets(用于合并和生成预览)。
问题是,我需要按照用户选择它们的顺序保留AVAssets,但“requestAVAsset”函数是异步的,并且通常多次调用完成处理程序。我以前从未使用过Dispatch Groups,但是试图在下面使用它们......并且AVAssets有时仍然无序。
func requestAVAssets(assets: [PHAsset]) -> [AVAsset] {
var videoArray: [AVAsset] = []
let dispatchGroup = DispatchGroup()
let videoOptions = PHVideoRequestOptions()
videoOptions.isNetworkAccessAllowed = true
videoOptions.deliveryMode = .fastFormat
for asset in assets {
dispatchGroup.enter()
self.imageManager.requestAVAsset(forVideo: asset, options: videoOptions, resultHandler: { (video, audioMix, info) in
guard video != nil else { return }
videoArray.append(video!)
dispatchGroup.leave()
})
}
dispatchGroup.wait()
return videoArray
}
我猜我错了一些代码或者以完全错误的方式接近它!任何建议都表示赞赏。
答案 0 :(得分:1)
完全躲避调度问题,因为它已经很晚了,而且我有一个糟糕的一天,但如果你保持与视频相关的“正确”索引然后排序呢?我觉得这样的事情会起作用。
struct SelectedVideo {
let index: Int
let asset: AVAsset
}
func requestAVAssets(assets: [PHAsset]) -> [AVAsset] {
var videoArray: [SelectedVideo] = []
let dispatchGroup = DispatchGroup()
let videoOptions = PHVideoRequestOptions()
videoOptions.isNetworkAccessAllowed = true
videoOptions.deliveryMode = .fastFormat
for (index, asset) in assets.enumerated() {
dispatchGroup.enter()
self.imageManager.requestAVAsset(forVideo: asset, options: videoOptions, resultHandler: { (videoMb, audioMixMb, infoMb) in
guard let video = videoMb else return
videoArray.append(SelectedVideo(index, video))
dispatchGroup.leave()
})
}
dispatchGroup.wait()
return videoArray.sort { $0.index < $1.index}.map({$0.video})
}
这是一种黑客攻击(甚至没有尝试编译它),但就像我说的那样,这是糟糕的一天。
一些小改动要注意:我将params改为闭包,说“Mb”,这意味着“也许”,这是一个很好的约定,我已经看到了传递给闭包的命名选项。此外,而不是“保护视频!= nil”,然后强制解包,更喜欢做“看守视频= videoMb”,然后视频是非可选的。
答案 1 :(得分:1)
如果在迭代AVAssets时捕获当前索引,则可以插入而不是追加。这就是我如何做到的,至少。
func requestAVAssets(assets: [PHAsset]) -> [AVAsset] {
var videoArray = [AVAsset?](repeating: nil, count: assets.count)
let videoOptions = PHVideoRequestOptions()
videoOptions.isNetworkAccessAllowed = true
videoOptions.deliveryMode = .fastFormat
for (i, asset) in assets.enumerated() {
self.imageManager.requestAVAsset(forVideo: asset, options: videoOptions, resultHandler: { (video, audioMix, info) in
guard let video = video else { return }
videoArray.remove(at: i)
videoArray.insert(video, at: i)
})
}
return videoArray.flatMap { $0 }
}
为数组提供所需数量的项目nil
将阻止其在插入项目时出错,然后在下载完成后删除现有的nil值并将其替换为实际的AVAsset
最后,flatMap生成的数组解压缩选项(并可选择通过将它与传入的assets
数组进行比较来检查您是否拥有所需数量的项目。)