繁体   English   中英

有没有一种方法可以停止流程,直到我从 Swift 中的 API 得到响应?

[英]Is there an method to stop the flow until I get response from API in Swift?

基本上,我们确实有一个 APIHelper 类,其中实现了 GET 和 POST 方法,可以从任何视图控制器调用,我们将在标头中发送一个访问令牌以确保安全,一旦该访问令牌过期,我们需要调用用于获取访问令牌的 API,需要在标头中发送更新的令牌。

class func postMethod(methodName: String, success: @escaping (AnyObject?, String?)->Void, Failure:@escaping (NSError)->Void)
{
    do {
        
        if ReachabilityManager.shared.isConnectedToNetwork() == false
        {
            PageNavigation.moveToInternet()
            
            
        } else {
            
            let session = URLSession.shared
            let urlPath = URL(string: "\(AppConstants.BaseUrl)" + "\(methodName)")
            var request = URLRequest(url: urlPath! as URL)
            
            print( "JSON request is \(urlPath!)")
            request.httpMethod = "POST"
            
            request = WebAPIHelper.headers(methodType: "POST", methodName: methodName, request: request, isAddUserAuthorization: false)
            
            let jsonBody = try JSONEncoder().encode(CommonDBHelper.getActiveUserRefreshToken())
            request.httpBody = jsonBody
            
            let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
                if(error == nil)
                {
                    do
                    {
                        if let httpResponse = response as? HTTPURLResponse
                        {
                            let headers = httpResponse.allHeaderFields
                            let statusCode = httpResponse.statusCode
                            
                             if (statusCode == 200)
                            {
                                let JSON = try JSONSerialization.jsonObject(with: data!, options:JSONSerialization.ReadingOptions.allowFragments)
                                
                                if let currentServerTime = headers["Date"] as? String
                                {
                                    success(JSON as AnyObject?, currentServerTime)
                                }
                                else{
                                    success(JSON as AnyObject?, nil)     // Closure being called as a function
                                }
                            }
                            
                            else
                            {
                                GenericMethods.showAlert(alertMessage: "Some error occured. Please try again later")
                            }
                        }
                        else
                        {
                            GenericMethods.showAlert(alertMessage: "Some error occured. Please try again later")
                        }
                    }
                    catch let JSONError as NSError
                    {
                        Failure(JSONError as NSError)
                        
                        print("JSON Error \(JSONError)")
                        GenericMethods.showAlert(alertMessage: "Some error occured. Please try again later")
                    }
                }
                else
                {
                    Failure(error! as NSError)
                    GenericMethods.showAlert(alertMessage: "Some error occured. Please try again later")
                }
            })
            task.resume()
        }
    }
    catch {
        print("Error in catch \(error.localizedDescription)")
    }
    
}

所以 GET & POST 将被多个线程一次调用,那么如何将所有调用保持在等待模式,直到我从 Access Token API 得到响应,这种类型的场景有什么解决方案吗?

class func headers(methodType:String, methodName:String, request:URLRequest, isAddUserAuthorization : Bool) -> URLRequest
{
    let methodName = methodName
    var request = request
    
    


        if isTokenExpired(){
            
            //how to keep waiting all other api calling in waiting mode here until i get response
            
            RefreshTokenAPI(completed: { (accesstoken) ->Void in
                request.addValue(accesstoken, forHTTPHeaderField: "AccessToken")
            })
            
        }
        else{
            request.addValue(getAccessTokenFromDefaults(), forHTTPHeaderField: "AccessToken")
        }
        
    
    
   
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")
    
    
    
    print(request.allHTTPHeaderFields!)
    
    return request as URLRequest
}

这里的目标是在您收到访问令牌后发起后续请求。 人们通常会使用完成处理程序模式,例如仅在检索到访问请求后调用的闭包:

class func headers(methodType: String, methodName: String, request: URLRequest, isAddUserAuthorization: Bool, completion: @escaping (URLRequest) -> Void) {
    var request = request

    // presumably you have code that is using methodType and methodName, too ...

    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    if isTokenExpired() { 
        refreshTokenAPI { accesstoken in
            request.addValue(accesstoken, forHTTPHeaderField: "AccessToken")
            completion(request)
        }
    } else {
        request.addValue(getAccessTokenFromDefaults(), forHTTPHeaderField: "AccessToken")
        completion(request)
    }
}

然后而不是:

request = WebAPIHelper.headers(methodType: "POST", methodName: methodName, request: request, isAddUserAuthorization: false)

...

// currently issuing request here

调用者将根据headers完成处理程序中的request移动所有内容:

WebAPIHelper.headers(methodType: "POST", methodName: methodName, request: request, isAddUserAuthorization: false) { request in
    // issue request here
    ...
}

// but not here

这是简单的“检索访问令牌后发起请求”模式。

你也可以追求其他模式。 例如,您可以为授权请求创建一个队列,该队列在RefreshTokenApi恢复该队列之前会暂停。 然后,所有需要令牌的请求都将添加到该队列中。 或者您可以使用自定义Operation模式,其中isReady在成功检索令牌时设置。 有很多方法可以给猫剥皮,但希望这说明了我们采用异步模式而不是“停止”或“等待”的想法。


如果您想确保允许并发请求调用refreshTokenAPI ,那么您可以让它等待,但只能在某些后台队列上执行此操作,并避免阻塞调用者线程:

private var queue = DispatchQueue(label: "com.domain.app.token") // custom serial queue to avoid blocking calling thread

func headers(methodType: String, methodName: String, request: URLRequest, isAddUserAuthorization: Bool, completion: @escaping (URLRequest) -> Void) {
    queue.async { [self] in
        var request = request

        // presumably you have code that is using methodType and methodName, too ...

        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")

        if isTokenExpired() {
            let semaphore = DispatchSemaphore(value: 0)

            refreshTokenAPI { token in
                request.addValue(token, forHTTPHeaderField: "AccessToken")
                DispatchQueue.main.async { completion(request) }
                semaphore.signal()
            }
            semaphore.wait()
        } else {
            request.addValue(getAccessTokenFromDefaults(), forHTTPHeaderField: "AccessToken")
            DispatchQueue.main.async { completion(request) }
        }
    }
}

坦率地说,我可能会考虑将这些网络请求包装在Operation (或使用 Combine)的自定义异步子类中,但这超出了本问题的范围。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM