Ios 请求Avasset时维持秩序

Ios 请求Avasset时维持秩序,ios,swift,grand-central-dispatch,photosframework,Ios,Swift,Grand Central Dispatch,Photosframework,我正在尝试构建一个视频合并应用程序,允许用户从集合视图中选择多个短片,然后生成所有合并到一个视频的预览。我正在使用照片框架(PHCachingImageManager)填充集合视图,并将所选相集的数组传递给下面的函数,以请求低质量的avasset(用于合并和生成预览) 问题是,我需要按照用户选择avasset的顺序保存avasset,但是“requestAVAsset”函数是异步的,并且通常会多次调用完成处理程序。我以前从未使用过调度组,但尝试在下面使用它们……而且AVAssets有时仍然不正常

我正在尝试构建一个视频合并应用程序,允许用户从集合视图中选择多个短片,然后生成所有合并到一个视频的预览。我正在使用照片框架(PHCachingImageManager)填充集合视图,并将所选相集的数组传递给下面的函数,以请求低质量的avasset(用于合并和生成预览)

问题是,我需要按照用户选择avasset的顺序保存avasset,但是“requestAVAsset”函数是异步的,并且通常会多次调用完成处理程序。我以前从未使用过调度组,但尝试在下面使用它们……而且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
}

我猜我不是把一些代码放错地方了,就是用了一种完全错误的方法!感谢您的任何建议。

完全回避发送问题,因为时间晚了,而且我今天过得不好,但是如果您保留与视频相关的“正确”索引,然后根据该索引进行排序,会怎么样?我想这样的事情会管用的

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})
}
struct SelectedVideo{
let索引:Int
出租资产:AVAsset
}
func RequestAvasset(资产:[PHAsset])->[AVAsset]{
var videoArray:[SelectedVideo]=[]
让dispatchGroup=dispatchGroup()
让videoOptions=PHVideoRequestOptions()
videoOptions.isNetworkAccessAllowed=true
videoOptions.deliveryMode=.fastFormat
对于assets.enumerated()中的(索引,资产){
dispatchGroup.enter()
self.imageManager.requestAVAsset(用于视频:资产,选项:视频选项,结果文件夹:{(视频MB,音频MIXMB,信息MB)中的
guard let video=videoMb else返回
videoArray.append(选定的视频(索引,视频))
dispatchGroup.leave()
})
}
dispatchGroup.wait()
返回videoArray.sort{$0.index<$1.index}.map({$0.video})
}
这是一种黑客行为(甚至还没有尝试编译),但正如我所说的,这是糟糕的一天


需要注意的几个小改动:我将闭包的参数改为“Mb”,意思是“maybe”,这是我见过的命名传递给闭包的选项的好习惯。此外,与“guard video!=nil”之后的强制展开不同,更倾向于执行“guard let video=videoMb”,然后视频是非可选的。

完全回避调度问题,因为时间太晚了,而且我今天过得不好,但是如果您保留与视频相关的“正确”索引,然后再进行排序,会怎么样?我想这样的事情会管用的

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})
}
struct SelectedVideo{
let索引:Int
出租资产:AVAsset
}
func RequestAvasset(资产:[PHAsset])->[AVAsset]{
var videoArray:[SelectedVideo]=[]
让dispatchGroup=dispatchGroup()
让videoOptions=PHVideoRequestOptions()
videoOptions.isNetworkAccessAllowed=true
videoOptions.deliveryMode=.fastFormat
对于assets.enumerated()中的(索引,资产){
dispatchGroup.enter()
self.imageManager.requestAVAsset(用于视频:资产,选项:视频选项,结果文件夹:{(视频MB,音频MIXMB,信息MB)中的
guard let video=videoMb else返回
videoArray.append(选定的视频(索引,视频))
dispatchGroup.leave()
})
}
dispatchGroup.wait()
返回videoArray.sort{$0.index<$1.index}.map({$0.video})
}
这是一种黑客行为(甚至还没有尝试编译),但正如我所说的,这是糟糕的一天


需要注意的几个小改动:我将闭包的参数改为“Mb”,意思是“maybe”,这是我见过的命名传递给闭包的选项的好习惯。此外,与“guard video!=nil”之后的强制展开不同,更倾向于执行“guard let video=videoMb”,然后视频是非可选的。

如果在迭代Avasset时捕获当前索引,则可以插入而不是追加。至少我是这样做的

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


最后,对结果数组进行平面映射以解压选项(并通过将其与传入的
资产
数组进行比较来检查是否具有所需的项数)。

如果在迭代Avasset时捕获当前索引,则可以插入而不是追加。至少我是这样做的

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


最后,将生成的数组进行平面映射以解包选项(并通过将其与传入的
资产
数组进行比较来检查您是否拥有所需数量的项目)。

谢谢Daniel,这非常有效。我想您的意思是将“videoArray[I]=video”改为“videoArray.insert(video,at:I)”,否则您将得到数组索引越界错误。我也不知道解包选项的平面映射快捷方式!:)这将教会我在没有静态分析器的情况下编写代码!您还需要使用
DispatchGroup
DispatchSemaphore
等待所有请求完成,然后再从函数返回(但我相信您已经解决了)。谢谢Daniel,这很有魅力。我想您的意思是将“videoArray[I]=video”改为“videoArray.insert(video,at:I)”,否则您将得到数组索引越界错误。我也不知道解包选项的平面映射快捷方式!:)这将教会我在没有静态分析器的情况下编写代码!您还需要您的
调度组
调度