我目前有一组异步函数,这些函数都在viewDidLoad()
中调用。在每个函数的末尾是一个bool,在函数完成后从false设置为true。还有一个条件语句检查两个函数的bool,它们触发第三个函数。这个条件语句在两个函数中(当两者的两个完成时我想要调用它)。一般为:
var checkOne = false
var checkTwo = false
func functionOne(){
//async stuff
checkOne = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
}
func functionTwo(){
//async stuff
checkTwo = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
}
func functionThree(){
//stuff
}
override func viewDidLoad() {
functionOne()
functionTwo()
}
此设置可确保{em}只能在 functionThree()
和functionOne
完成后才能运行functionTwo
。如果functionOne
在functionTwo()
之前完成其异步内容并且到达条件以触发functionThree()
,则不会执行此操作,因为checkTwo
尚未生效。因此,当functionTwo()
的异步内容完成时,它将触发functionThree()
。这适当地工作,并没有引起一次问题。但是,我想要明确避免的是异步函数正在完成,因此在完全同时调用functionThree()
。要做到这一点,我想设置一个NSLock()
,但是,尽管查阅了文档,但我不知道如何做到这一点,因为我需要由两个不同的函数处理相同的锁。有人有什么想法吗?
答案 0 :(得分:14)
NSLock
是mutex;它可以防止多个线程同时访问同一个资源,这正是你想要在这里做的。一旦一个线程获得锁定,其他尝试获取锁定的线程将等到第一个线程释放锁定。
您希望创建一个锁并将其存储在函数调用之间和之间的某个地方,在这种情况下很可能是在实例变量中。要获取锁定,请调用其lock
方法并释放它,使用unlock
:
var checkOne = false
var checkTwo = false
//create the lock
let lock = NSLock()
func functionOne(){
//async stuff
//acquire the lock
lock.lock()
checkOne = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
//release the lock
lock.unlock()
}
func functionTwo(){
//async stuff
lock.lock()
checkTwo = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
lock.unlock()
}
func functionThree(){
//stuff
}
override func viewDidLoad() {
functionOne()
functionTwo()
}
更多"现代"方法是使用DispatchQueue
而不是NSLock
。 Dispatch比NSLock和NSThread等API更高级别;而不是直接使用锁和线程,你将使用队列。
串行调度队列就像商店的结账行一样。您向队列提交代码块,并按接收顺序一次执行一个代码块。您还可以创建一个并发调度队列,通过将.concurrent
传递给options
初始化程序的DispatchQueue
参数来同时执行其任务。
串行调度队列是一种保护资源不被多个线程同时访问的简单方法 - 只需为该资源创建一个队列,并将该资源的每次访问权限放在队列中。
var checkOne = false
var checkTwo = false
//Create a serial dispatch queue
let queue = DispatchQueue(label: "name of queue")
func functionOne(){
//async stuff
//Add a task to the queue, and execute it synchronously (i.e. wait for it to finish.)
//You can also use async to execute a task asynchronously,
//but sync is slightly more efficient unless you need it to be asynchronous.
queue.sync {
checkOne = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
}
}
func functionTwo(){
//async stuff
queue.sync {
checkTwo = true
if checkOne == true && checkTwo == true{
functionThree()//will only run if both functionOne and functionTwo have been completed
}
}
}
func functionThree(){
//stuff
}
override func viewDidLoad() {
functionOne()
functionTwo()
}
答案 1 :(得分:1)
使用DispatchGroup的另一种方法。更简单,恕我直言。
class ViewController: UIViewController {
let group = DispatchGroup()
override func viewDidLoad() {
super.viewDidLoad()
group.enter()
functionOne()
group.enter()
functionTwo()
group.notify(queue: .global(qos: .default), execute: { [weak self] in
self?.functionThree()
})
}
func functionOne() {
//async stuff
group.leave()
}
func functionTwo() {
//async stuff
group.leave()
}
func functionThree() {
//stuff
}
}