如何利用NSLock防止函数触发两次?

Ale*_*cki 6 asynchronous nslock swift

我目前有一组异步函数,它们都被调用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()
}
Run Code Online (Sandbox Code Playgroud)

这种设置保证functionThree()时才能运行 functionOnefunctionTwo完成.如果functionOne之前完成其异步内容functionTwo()并且获得条件触发functionThree(),它将不会执行它,因为checkTwo尚未实现.因此,当functionTwo()异步的东西完成时,它会触发functionThree().这适当地工作,并没有引起一次问题.我想明确避免的,虽然是异步功能发生完成,因此呼吁functionThree(),在确切的同一时间.为了做到这一点,我想设置一个NSLock(),但是,尽管查找文档,我没有线索如何做到这一点,因为我需要由两个不同的功能处理相同的锁.有人有主意吗?

Nob*_*ica 19

An NSLock互斥体 ; 它可以防止多个线程同时访问同一个资源,这正是你想要在这里做的.一旦一个线程获得锁,其他尝试获取锁的线程将等到第一个线程释放锁.

您将需要创建一个锁并将其存储在函数调用之间和之间的某个地方,在这种情况下很可能是在实例变量中.要获取锁定,调用其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()
}
Run Code Online (Sandbox Code Playgroud)

更"现代"的方法是使用a DispatchQueue而不是a 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()
}
Run Code Online (Sandbox Code Playgroud)


小智 8

另一种方法是使用 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
    }
}
Run Code Online (Sandbox Code Playgroud)