我有2个委托方法,这些方法是通过来自第三方库的通知调用的。
方法1:
mediaContentWasUpdated()
方法2:
adMediaDidBeginPlaying()
在方法1中,键参数(adDuration
)是根据随通知传入的参数设置的。据我所知,这是获取此信息的唯一地方。
在方法2中,我们检查adDuration
,如果它大于0,那么我们会更新用户界面,以反映我们实际上是在播放广告。
出现了一个错误,有时会以错误的顺序调用这两个方法。这意味着未设置adDuration
,方法2认为没有要播放的广告媒体,也没有相应地更新用户界面。
我目前对解决方案的尝试是使adDuration
可选并使用NSCondition使方法2等待方法1设置adDuration
然后继续。
var adDuration : Double?
let condition = NSCondition()
func mediaContentWasUpdated(notification: NSNotificiation) {
condition.lock()
if(notificationHasAdDurationInfo(notification)) {
self.adDuration = getAdDuration(notification)
condition.signal()
}
condition.unlock()
}
func adMediaDidBeginPlaying(notification: NSNotification) {
condition.lock()
while adDuration == nil {
condition.wait()
}
if adDuration! > Double(0) {
updateUIForAd()
}
condition.unlock()
}
这是我第一次尝试这样的事情,我担心我做错了什么。我也有一些关于不必要地锁定和解锁线程的担忧(这会在适时的运行中发生,或者如果没有要播放的广告内容)。
外部因素阻碍了我的测试能力,我希望得到一些意见,看看我是否朝着正确的方向前进,同时等待这些问题得到解决。
答案 0 :(得分:1)
你对NSCondition的讨论让我和你在同一条轨道上,我使用DispatchGroup构建了两个或三个解决方案(这是更好的工具),但是他们总是有很少的角落情况可能表现得很糟糕,而且没有真的抓住了意图。
(如果您对DispatchGroup解决方案感兴趣,可以选择以下形式:在.enter()
中致电init
,在持续时间到来时致电.leave()
,致电{{1当播放开始时。它工作正常,但它会引入可能崩溃的极端情况,就像notify()
一样。)
回到真正的意图:
在知道持续时间且广告已开始播放时更新用户界面。
这里没有并发性。所以拔出GCD不仅仅是矫枉过正;它实际上使事情变得更糟,因为它引入了许多复杂的角落案例。
所以我想到了如何在GCD之前解决这个问题。答案显而易见:只需检查您是否拥有所需的数据,然后再进行操作。 (阅读评论,我看到Paulw11也指出了这一点。)
我个人喜欢将这种东西拉成自己的类型,以使事物更加独立。我讨厌这里的一些名字,但这个想法应该是明确的:
NSCondition
设置每个内容时,看看是否准备好更新,如果是,请更新。我已经摆脱了可选项,因为我认为意图是“0持续时间总是错误的”。但是您可以使用Optional,这样您就可以检测到实际从通知中收到0。
有了这个,你只需设置一个玩家属性:
class AdPlayer {
private var readyToPlay = false
private var duration: Double = 0.0
private let completion: (Double) -> Void
func setDuration(from notification: Notification) {
if(notificationHasAdDurationInfo(notification)) {
duration = getAdDuration(notification)
}
playIfReady()
}
func play() {
readyToPlay = true
playIfReady()
}
private func playIfReady() {
if duration > 0 && readyToPlay {
completion(duration)
}
}
init(completion: @escaping (Double) -> Void) {
self.completion = completion
}
}
(请注意,以上内容可能会创建一个保留循环,具体取决于player = AdPlayer(completion: updateUIForAd)
;您可能需要updateUIForAd
闭包等。)
然后根据需要更新它:
[weak self]
创建func mediaContentWasUpdated(notification: NSNotificiation) {
player.setDuration(from: notification)
}
func adMediaDidBeginPlaying(notification: NSNotification) {
player.play()
}
类型的一大优势是,在广告完成后(或出现问题时)可以轻松重置系统。扔掉整个物体然后再制造另一个物体。