正确使用Alamofire队列

时间:2017-03-02 23:19:00

标签: swift alamofire grand-central-dispatch

这是一个场景,一切正常,但我被挂在主队列上。我有:

  1. 用于管理API连接的单例类。一切正常(暂时执行时间......)
  2. 许多视图控制器通过上面的单例类调用GET API来获取数据
  3. 我通常从viewDidLoad或viewWillAppear
  4. 调用上述内容
  5. 他们都工作但是....
  6. 如果我用Alamofire.request()调用一些带有闭包的API方法(好吧,我需要知道它何时是 时间重新加载!),其中一个挂起等待默认值 (主)队列给它一个线程,最多可能需要20秒
  7. 如果我只打一个,做我的事,然后调用POST API,这个     后者最终与(5)的情况相同,需要很长时间     是时候抓住默认队列中的一个插槽了。
  8. 我没有在Alamofiore.request()中指定一个队列,这听起来像我应该这样,所以我尝试了。我在我的单例API类中添加了一个自定义并发队列,我尝试将其添加到我的Alamofiore.request().....并且没有做任何事情。请帮忙,我一定要错过一些明显的东西?!

    这是我的单例API管理器(摘录)类:

    class APIManager {
    // bunch of stuff here
    
    static let sharedInstance = APIController()
    // more stuff here
    
    let queue = DispatchQueue(label: "com.teammate.response-queue", qos: .utility, attributes: [.concurrent])
    // more stuff
    
    func loadSports(completion: @escaping (Error?) -> Void) {
    
            let parameters: [String: Any?] = [:]
            let headers = getAuthenticationHeaders()
            let url = api_server+api_sport_list
            Alamofire.request(url, method: .get, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseString (queue: queue) { response in
                if let json = response.result.value {
                    if let r = JSONDeserializer<Response<[Sport]>>.deserializeFrom(json: json) {
                        if r.status == 200 {
                            switch r.content{
                            case let content as [Sport]:
                                self.sports = content
                                NSLog("sports loaded")
                                completion(nil)
                            default:
                                NSLog("could not read the sport list payload!")
                                completion(GenericError.reportError("could not read sports payload"))
                            }
                        }
                        else {
                            NSLog("sports not obtained, error %d %@",r.status, r.error)
                            completion(GenericError.reportError(r.error))
                        }
                    }
                }
            }
        }
    
    // more stuff
    }
    

    这就是我得到sigleton时从APIManager调用方法的方法:

    api.loadSports(){ error in
      if error != nil {
        // something bad happened, more code here to handle the error
      }
      else {
          self.someViewThingy.reloadData()
      }
    }
    

    同样,这一切都有效,只是如果我从同一个UIViewController进行多次Alamofire调用,第一个是快速的,每隔一个调用就是为了让队列中的一个点运行。

1 个答案:

答案 0 :(得分:2)

UI updates must happen on the main queue, so by moving this stuff to a concurrent queue is only going to introduce problems. In fact, if you change the completion handler queue to your concurrent queue and neglect to dispatch UI updates back to the main queue, it's going to just make it look much slower than it really is.

I actually suspect you misunderstand the purpose of the queue parameter of responseString. It isn't how the requests are processed (they already happen concurrently with respect to the main queue), but merely on which queue the completion handler will be run.

So, a couple of thoughts:

  1. If you're going to use your own queue, make sure to dispatch UI updates to the main queue.

  2. If you're going to use your own queue and you're going to update your model, make sure to synchronize those updates with any interaction you might be doing on the main queue. Either create a synchronization queue for that or, easier, dispatch all model updates back to the main queue.

  3. I see nothing here that justifies the overhead and hassle of running the completion handler on anything other than the main queue. If you don't supply a queue to responseString, it will use the main queue for the completion handlers (but won't block anything, either), and it solves the prior two issues.