仅当函数完成创建它们时才从视频中检索 UIImage - swift - swift 以编程方式
Retrieving UIImage from video only when function completed creating them - swift - swift programmatically
我正在使用 generateCGImagesAsynchronouslyForTimes
从视频创建 UIImages
:
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()
被调用多次。
我想实现 completion()
仅在创建所有图像(在本例中为 7 个)后调用。
我该怎么做?
您需要使用一个DispatchGroup
来等待多个异步函数完成。您需要确保对 DispatchGroup.enter()
和 leave()
的调用是平衡的(调用相同的次数),因为当您使用 dispatchGroup.notify(queue:)
时,闭包只会执行一次 leave()
已为每个 enter()
.
您需要为 times
数组的每个元素调用 enter
(它将包含 CMTime
变量 time1
到 time7
,然后在generateCGImagesAsynchronously(forTimes:
的完成块,你调用 leave()
。这确保了 notify(queue:)
只会在 generateCGImagesAsynchronously
为所有图像调用它自己的完成后才执行它的关闭。
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)
let times = [NSValue(time: time1), NSValue(time: time2), NSValue(time: time3), NSValue(time: time4), NSValue(time: time5), NSValue(time: time6), NSValue(time: time7)]
var imageArray : [UIImage] = []
let dispatchGroup = DispatchGroup()
times.forEach { _ in
dispatchGroup.enter()
}
imageGenerator.generateCGImagesAsynchronously(forTimes: times) { (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)
dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
completion(imageArray)
}
}