【问题标题】:Issue while calling mutlile API in swift 3?在 swift 3 中调用多重 API 时出现问题?
【发布时间】:2018-02-14 11:26:32
【问题描述】:

我有两个类。A 类和 B 类。在 A 类中有表格视图。当我点击 A 类中的单元格时,我调用第一个 api 来保存数据/saveData & 在第一个 api 的响应中我调用另一个api getData。我在后台调用这些 API。现在,当我移动到 A 类时,我在 viewDidLoad() 上调用另一个 API。我在前台调用它。现在我希望 A 类的 API 不应该影响 B 类.

请告诉最好的方法是什么。

我尝试了DispatchGroup,但对我不起作用。

    func saveInBackground(parameter : [String : AnyObject]?) -> Void {

        let group = DispatchGroup()
        group.notify(queue: DispatchQueue.global(qos: .background)){

            let apiManager = APIHandler(baseURL: Constants.API.baseURL, APIVersion: "")

            apiManager.requestOfBgMethod(.post, path: Constants.API.Name.addGeneralField.completePath, parameters: parameter, encoding: .url, headers: nil, apiSuccess: { (result) in
                //update user
                self.copyUser = User(copyFrom: self.user)
                self.saveCVResponse(result: result)
                //fetch data in background
                Utility.sharedInstance.updateCVdata(cvManager: self.cvManager)
            }, apiFailure: { (error) in

            })
        }

//        DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {
//            
//
//        }
    }

【问题讨论】:

    标签: ios swift api alamofire


    【解决方案1】:

    使用DispatchSemaphore和一个Singleton实例,让API一一调用:

    class ApiHelper {
        static let shardInstance = ApiHelper()
        private let semaphore = DispatchSemaphore(value: 1) //one task allowed at a time
        private let apiManager = APIHandler(baseURL: Constants.API.baseURL, APIVersion: "")
    
        func saveInBackground(parameter : [String : AnyObject]?) -> Void {
            DispatchQueue.global(qos: .default).async { [unowned self] in
                self.semaphore.wait() //lock
    
                apiManager.requestOfBgMethod(.post, path: Constants.API.Name.addGeneralField.completePath, parameters: parameter, encoding: .url, headers: nil, apiSuccess: { (result) in
                    //.......
                    self.semaphore.signal()  //unlock
                }, apiFailure: { (error) in
                    self.semaphore.signal()  //unlock
                })
            }
        }
    }
    

    A类和B类使用,互不影响:

    ApiHelper.shardInstance.saveInBackground(parameter: nil) 
    

    【讨论】:

    • 对于这种情况,我必须更改整个 API 结构,这非常复杂且耗时。因为后台和前台 api 不使用相同的方法
    • 你能修改类APIHandler 吗?也许这个类应该提供一个单例来做到这一点。
    • 或者你可以定义一个DispatchSemaphore的全局变量,直接在你的saveInBackground方法中使用。
    【解决方案2】:

    使用不带单例的全局DispatchSemaphore

    在A类或B类或某处,定义一个类外的全局信号量:

    let semaphoreGlobal = DispatchSemaphore(value: 1) //one task at a time
    
    //ignore following, just an example.
    class AnyClass {
        //......
    }
    

    你的方法变成了:

    func saveInBackground(parameter : [String : AnyObject]?) -> Void {
        DispatchQueue.global(qos: .default).async {
            semaphoreGlobal.wait() //wait if semaphore is 0. Else, set semaphore to 0 and continue.
    
            //remember: the variable 'apiManager' should not be a local one.
            apiManager.requestOfBgMethod(.post, path: Constants.API.Name.addGeneralField.completePath, parameters: parameter, encoding: .url, headers: nil, apiSuccess: { (result) in
                //.......
                semaphoreGlobal.signal()  //set semaphore to 1, means allowing one of other tasks stops waiting.
            }, apiFailure: { (error) in
                semaphoreGlobal.signal()  //set semaphore to 1
            })
        }
    }
    

    【讨论】:

    • 这种情况会发生什么?它会等待从任何其他方法调用的其他 api 吗?我应该在多个类中使用相同的信号量对象吗?我不明白如何遵循您的方法
    • 在这种情况下,在这个方法和任何其他方法中,一次只执行一个在.wait().signal()之间的代码块。其他的将等待前一个块发送信号通过signal()。是的,您应该在多个类中使用相同的信号量对象,这就是它是全局的原因。
    • 我更新了 cmets 以供您参考。
    • 我如何在没有单例的情况下使用全局。因为在这种情况下我将无法访问信号对象
    • 在任何地方定义对象,而不是在类中。然后它是全球性的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多