使用操作来管理函数调用之间的不平衡

问题描述

我正在编写一个 VideoPlayer() 类,该类具有 start()stop() 函数来启动给定视频的播放。 VideoPlayer() 的每个实例管理一个视频

start()stop() 函数是异步的,我通过成功/失败的委托得到通知。此委托由第三方 SDK 完成。

class VideoPlayer {
    func start() {
     // Async call
    }

    func stop() {
     // Async call
    }

    // Callback from third party library with status
    func videoDidStart(view: UIView) {
       // Notify clients
     }
      
     func videoDidStop(stopped: Bool) {
       // Notify clients
     }

}

我有客户调用 start()stop() 函数,但有时碰巧他们会快速连续调用 start/stop。这会导致意外行为。 例如,如果客户端在上一次调用 start() 之前调用 stop(),视频将不会播放。

理想情况下,客户端会等到我发送通过代表收到的成功/失败通知。

当然,这不会发生,我的任务是让 VideoPlayer() 类管理 start()stop() 之间的不平衡,并将所有调用排队,以便一切按顺序执行。

我希望 VideoPlayer() 类确保每次 start()stop() 之间出现不平衡时,每个 start() 都与一个 stop() 匹配并且将流氓调用放入队列中,并在解决不平衡问题后执行它们。

我如何管理这样的事情?我相信我需要使用 Operationsstart()stop() 之间的依赖关系。我是否应该将 start()/stop() 设为单个操作并将恶意调用排入队列,直到操作完成。

我可以使用其他方法吗?我查看了 dispatch_groupsdispatch_barriers,但不确定它们是否适合我的用例。

任何帮助将不胜感激。谢谢

解决方法

我不明白为什么需要手术。作为您所描述的那种事情的粗略示例,我制作了一个小型调度程序架构:

struct Start {
    let callback : () -> ()
    var started = false
}
class Dispatcher {
    var q = [Start]()
    func start(_ f: @escaping () -> ()) {
        q.append(Start(callback:f))
        self.startFirstOne()
    }
    func stop(_ f: @escaping () -> ()) {
        // assume this can only refer to the first one in the queue
        DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
            self.q.removeFirst()
            f()
            self.startFirstOne()
        }
    }
    private func startFirstOne() {
        guard !q.isEmpty else { return }
        guard !q[0].started else { return }
        print("starting")
        self.q[0].started = true
        DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
            self.q.first!.callback()
        }
    }
}

start 调用已排队,在收到足够多的 stop 调用以将其置于队列前面之前,我们实际上不会启动调用。

我个人根本不喜欢这个,因为我们对合同遵守做出了三个非常强烈的假设:

  • 我们假设每个调用 start 的人也会调用 stop

  • 并且我们假设调用 start 的人在从 stop 调用中被回调之前不会调用 start

  • 而且我们假设没有调用 start 的人永远不会调用 stop

然而,如果每个人都确实遵守合同,那么每个人的 stop 都会被回调对应于该人的 start。这是一个粗略的测试平台,使用随机延迟来模拟异步性:

let d = Dispatcher()
DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
    d.start {
        print("hearts start")
        DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
            d.stop { print("hearts stop") }
        }
    }
}
DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
    d.start {
        print("diamonds start")
        DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
            d.stop { print("diamonds stop") }
        }
    }
}
DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
    d.start {
        print("clubs start")
        DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
            d.stop { print("clubs stop") }
        }
    }
}
DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
    d.start {
        print("spades start")
        DispatchQueue.main.asyncAfter(deadline: .now()+DispatchTimeInterval.seconds(Int.random(in: 1...10))) {
            d.stop { print("spades stop") }
        }
    }
}

试试看,你会发现,无论这些东西运行的顺序和时间如何,开始-停止对都由调度员维护。

正如我所说,我不喜欢它。我更愿意假设来电者可能遵守合同并准备对此采取行动。但这就是它的价值。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...