我正在处理一个小问题:同时获取一堆有序数据并以正确的顺序输出(具体来说,获取.ts
个文件的负载,通过{{1按照正确的顺序,但这是偶然的)。想要将重新排序(按顺序传递碎片)和管道(让ffmpeg做它的事情)分开,我把它写成两个对象:
ffmpeg
和
struct Aggregator<ChunkType> {
private var currentIdx = 0
private var chunks: [Int:ChunkType] = [:]
private let serializer: Serializer
init(serializer: Serializer) where Serializer.ChunkType == ChunkType {
// self.serializer = serializer
}
private let queue = DispatchQueue(label: "Serial")
mutating func accept(chunk:ChunkType, forIndex idx: Int) {
// One accessor at a time
queue.sync {
chunks[idx] = chunk
// Forward zero or more chunks
while chunks[currentIdx] != nil {
//serializer.append(chunk: chunks.removeValue(forKey: currentIdx))
currentIdx += 1
}
}
}
}
有两个实现:
protocol Serializer {
associatedtype ChunkType
func append(chunk: ChunkType)
}
最终目标是使用看起来像:
// For capturing the output of an Aggregator<Int> to check it's working as intended
class IntArraySerializer: Serializer {
typealias ChunkType = Int
var allInts = [Int]()
func append(chunk: ChunkType) {
allInts.append(chunk)
}
}
// For piping output through ffmpeg
class FFMPEGSerializer: Serializer {
typealias ChunkType = Data
private let ffmpegBin = "/usr/local/bin/ffmpeg"
private let ffmpeg: Process
private let stdin: Pipe
init(args: [String]) throws {
ffmpeg = Process()
ffmpeg.launchPath = ffmpegBin
ffmpeg.arguments = args
stdin = Pipe()
ffmpeg.standardInput = stdin
}
func append(chunk: Data) {
stdin.fileHandleForWriting.write(chunk)
}
}
然而,我对相关类型,泛型和可能的类型擦除的理解(如果确实是这里的解决方案)阻止我最终确定let ffmpeg = FFMPEGSerializer(["-i", "-", "-c", "copy", "-bsf:a aac_adtstoasc", "output.mp4"])
let aggregator = Aggregator(serializer: ffmpeg)
for (idx, url) in someListOfUrls.enumerated() {
concurrentQueue.async {
fetch(url) { data in
aggregator.accept(chunk: data)
}
}
}
,从各种注释行可以看出。我已经完成了关于类型擦除的一些阅读(例如this Big Nerd Ranch article),但我还没有理解我是否应该尝试在我的情况下应用它。
将其归结为一个陈述:我希望Aggregator
的{{1}}通知ChunkType
的泛型类型。
答案 0 :(得分:0)
由于错误消息明确说明,您无法使用协议Serializer
来注释属性或参数的类型。
我不明白你对 type-erasure 的意思,所以我可能会误解你的意思,但就我读你的代码而言,你可以轻松修复你的Aggregator
使用泛型:
//Make `S` a generic parameter constrained to `Serializer`
struct Aggregator<S: Serializer> {
//`ChunkType` needs always to be the same type as `S.ChunkType`
typealias ChunkType = S.ChunkType
private var currentIdx = 0
private var chunks: [Int: ChunkType] = [:]
//You can use `S` as a type of properties...
private let serializer: S
//...or a type of parameters.
init(serializer: S) {
self.serializer = serializer
}
private let queue = DispatchQueue(label: "Serial")
mutating func accept(chunk: ChunkType, forIndex idx: Int) {
// One accessor at a time
queue.sync {
chunks[idx] = chunk
// Forward zero or more chunks
while chunks[currentIdx] != nil {
serializer.append(chunk: chunks.removeValue(forKey: currentIdx)!)
currentIdx += 1
}
}
}
}