iOS Swift中的信号灯



我在iOS上使用信号量时遇到了一个问题。我正在实现一个功能,以便按顺序执行一系列异步方法。

let semaphore = DispatchSemaphore(value: 1)
semaphore.wait()
performFirstTask {
semaphore.signal
}
semaphore.wait()
performSecondTask {
semaphore.signal
}
semaphore.wait()
performThirdTask {
semaphore.signal
}

因此,这是按预期工作的,但如果用户在等待状态下离开屏幕,就会出现问题,因此当特定任务的回调触发时,视图可能已经解除分配,从而导致崩溃,有人能帮我解决这个问题吗?我看不出有任何方法可以释放信号量。

提前感谢

这个基于信号量的代码应该退役。现在我们使用Swift并发的async-await。请参阅Swift中的WWDC 2021视频Meet async/await,以及该页面上引用的其他视频。

如果您出于某种原因没有考虑Swift并发(即,您需要支持不支持async-await的操作系统版本(,您可能会考虑Combine,或自定义异步Operation子类,或许多第三方解决方案(例如,promise或futures(。但如今,信号量是一种反模式。

使用信号量有很多问题:

  • 它效率低下(因为它不必要地占用了线程(
  • 如果不小心,它会带来死锁风险
  • 如果你在主线程上这样做,可能会导致不合格的用户体验和/或看门狗进程杀死你的应用程序

话虽如此,问题很可能是当信号量的值小于创建时的值时(例如,您创建的信号量值为1,在释放时可能为0(,信号量被释放。看见https://stackoverflow.com/a/70458886/1271826.

您可以通过从零开始来避免这个问题。要做到这一点,您需要:

  1. 删除第一个wait:

    let semaphore = DispatchSemaphore(value: 0)   // not 1
    // semaphore.wait()
    performFirstTask {
    semaphore.signal()
    }
    semaphore.wait()
    performSecondTask {
    semaphore.signal()
    }
    …
    
  2. 或者,如果你需要第一个wait,只需先做一个signal:

    let semaphore = DispatchSemaphore(value: 0)    // not 1
    semaphore.signal()                             // now bump it up to 1
    semaphore.wait()
    performFirstTask {
    semaphore.signal()
    }
    semaphore.wait()
    performSecondTask {
    semaphore.signal()
    }
    …
    

同样,您应该完全停止使用信号量,但如果必须,您可以使用这两种技术中的任何一种,以确保释放时的计数不小于初始化时的计数。

让我们想象一下,您决定采用Swift并发,而不是使用信号量。那么,async-await会是什么样子呢?

让我们想象一下,您重构了performFirstTaskperformSecondTaskperformThirdTask以采用Swift并发。然后,您完全消除了信号量,您的15行代码被简化为:

Task {
await performFirstTask()
await performSecondTask()
await performThirdTask()
}

这将按顺序执行这三个异步任务,但避免了信号量的所有缺点。async-await的全部思想是,您可以非常优雅地表示一系列异步任务之间的依赖关系。

现在,您通常会重构performXXXTask方法以采用Swift并发。或者,您也可以为它们编写async"包装器"函数,例如:

func performFirstTask() async {
await withCheckedContinuation { continuation in
performFirstTask() {
continuation.resume(returning: ())
}
}
}

这是调用完成处理程序格式副本的performFirstTaskasync格式副本。

无论您决定如何做(重构这三个方法,或者只为它们编写包装器(,Swift并发都大大简化了过程。请参阅WWDC 2021视频Swift并发:更新示例应用程序,了解更多关于如何转换遗留代码以采用Swift并发的示例。

相关内容

  • 没有找到相关文章

最新更新