Swift:带有完成处理程序的多线程

Swift: Multithreading with Completion Handler

我有一个访问关键变量的函数并且需要对其进行互斥访问,但是 returns 通过完成处理程序。

这是我目前用来尝试的方法:

static func getAccessTokenValue(completionHandlerResult : @escaping (_ accesstoken:String) -> ()) {
    tokenQ.sync {
        let expire_in_str =  UserDefaults.standard.value(forKey: "expires_in") as! String
        print(expire_in_str)
        let accessToken_time = UserDefaults.standard.value(forKey: "access_token_time") as! Date

        let todayDate = Date()
        let seconds = (Calendar.current as NSCalendar).components(.second, from: accessToken_time, to: todayDate, options: []).second
        if  seconds! < Int(5) {
            print("success")
            completionHandlerResult( Constants.Access_Token)
        }
        else {
            refreshLock.wait()
            self.renewAccessToken(completionHandler: { accesstokenValue in
                tokenQ.sync {
                    completionHandlerResult(accesstokenValue)
                }
            })
            refreshLock.signal()
        }
    }
}

目标是一次只有一个线程能够使用 self.renewAccessToken。单独使用 DispatchQueue.sync 并不能实现这一点,所以我转向信号量,但上面的代码导致死锁,因为 refreshLock.signal() 似乎没有效果。

self.renewAccessToken 使用 alamofire 并在其中包含另一个完成处理程序,这增加了线程问题。

我遇到的主要问题 运行 是多个线程正在尝试同时更新同一个令牌,一旦一个线程更新了令牌,其他线程保留旧令牌并且他们的更新请求被拒绝因为令牌只能更新一次。

处理这种情况的最佳方法是什么?

试试这个:

static func getAccessTokenValue(completionHandlerResult : @escaping (_ accesstoken:String) -> ()) {
    tokenQ.sync {
        let expire_in_str =  UserDefaults.standard.value(forKey: "expires_in") as! String
        let accessToken_time = UserDefaults.standard.value(forKey: "access_token_time") as! Date

        let todayDate = Date()
        let seconds = (Calendar.current as NSCalendar).components(.second, from: accessToken_time, to: todayDate, options: []).second
        if  seconds! < Int(5) {
            completionHandlerResult( Constants.Access_Token)
        }
        else {
            refreshLock.wait()
            self.renewAccessToken(completionHandler: { accesstokenValue in
                    completionHandlerResult(accesstokenValue)
            })
            refreshLock.signal()
        }
    }
}