问题描述
我正在使用UIImages
通过视频创建generateCGImagesAsynchronouslyForTimes
:
fileprivate func createImageFramesFromVideo(completion: @escaping ([UIImage]) -> Void) {
guard let url = self.videoUrl else {
return
}
let asset = AVAsset(url: url)
let imageGenerator = AVAssetImageGenerator(asset: asset)
let videoDuration = asset.duration
//getting image snapshots more or less in half the video
let time1 = CMTime(value: videoDuration.value/2 - videoDuration.value/10,timescale: videoDuration.timescale)
let time2 = CMTime(value: videoDuration.value/2 - videoDuration.value/11,timescale: videoDuration.timescale)
let time3 = CMTime(value: videoDuration.value/2 - videoDuration.value/12,timescale: videoDuration.timescale)
let time4 = CMTime(value: videoDuration.value/2,timescale: videoDuration.timescale)
let time5 = CMTime(value: videoDuration.value/2 + videoDuration.value/12,timescale: videoDuration.timescale)
let time6 = CMTime(value: videoDuration.value/2 + videoDuration.value/11,timescale: videoDuration.timescale)
let time7 = CMTime(value: videoDuration.value/2 + videoDuration.value/10,timescale: videoDuration.timescale)
var imageArray : [UIImage] = []
imageGenerator.generateCGImagesAsynchronously(forTimes: [NSValue(time: time1),NSValue(time: time2),NSValue(time: time3),NSValue(time: time4),NSValue(time: time5),NSValue(time: time6),NSValue(time: time7)]) { (time,image,time1,result,err) in
if let err = err {
print("there's an error in retrieving the images",err)
}
let theImage = UIImage(cgImage: image!)
imageArray.append(theImage)
if(result == .succeeded){
completion(imageArray)
}
}
}
由于该函数的完成处理程序被称为每次,因此创建了新图像,因此completion()
被多次调用。
我想实现仅在创建所有图像(在本例中为7个)之后调用completion()
。
我该怎么办?
解决方法
您需要使用DispatchGroup
等待多个异步功能完成。您需要确保对DispatchGroup.enter()
和leave()
的调用是均衡的(调用相同的次数),因为当您使用dispatchGroup.notify(queue:)
时,闭包将只执行一次{{1 }}已被每个leave()
调用。
您需要为enter()
数组的每个元素调用enter
(它将包含times
变量CMTime
到time1
,然后在完成时time7
的块中调用generateCGImagesAsynchronously(forTimes:
,这确保leave()
仅在notify(queue:)
调用所有图像自己的完成功能后才执行其关闭操作。
generateCGImagesAsynchronously