正确使用 Alamofire 队列

Posted

技术标签:

【中文标题】正确使用 Alamofire 队列【英文标题】:proper use of Alamofire queue 【发布时间】:2017-03-02 23:19:00 【问题描述】:

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

    管理 API 连接的单例类。一切正常(除了执行时间......) 多个视图控制器通过上述单例类调用 GET API 来获取数据 我通常从 viewDidLoad 或 viewWillAppear 调用上述方法 它们都可以工作,但是 .... 如果我用闭包调用几个用 Alamofire.request() 实现的 API 方法(嗯,我需要知道它是什么时候 是时候重新加载了!),两者之一挂起等待默认 (main) queue 给它一个线程,它可能需要长达 20 秒 如果我只调用一个,做我的事,然后调用一个 POST API,这个 后一种情况与(5)相同,需要很长时间 是时候在默认队列中抢占一个位置了。

我没有在 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】:

UI 更新必须在主队列上进行,因此将这些内容移至并发队列只会带来问题。事实上,如果您将完成处理程序队列更改为并发队列,而忽略将 UI 更新分派回主队列,它只会让它看起来比实际慢得多。

我实际上怀疑你误解了responseStringqueue 参数的用途。这不是处理请求的方式(它们已经相对于主队列同时发生),而仅仅是完成处理程序将在哪个队列上运行。

所以,有几个想法:

    如果您要使用自己的队列,请确保将 UI 更新分派到主队列。

    如果您要使用自己的队列并且要更新模型,请确保将这些更新与您可能在主队列上进行的任何交互同步。要么为此创建一个同步队列,要么更简单地将所有模型更新分派回主队列。

    我在这里看不到任何可以证明在主队列以外的任何东西上运行完成处理程序的开销和麻烦。如果您不向 responseString 提供队列,它将使用主队列作为完成处理程序(但也不会阻塞任何内容),并且它解决了前两个问题。

【讨论】:

谢谢罗伯。事实上,我似乎误解了队列的目的。不管有没有它,我仍然有问题,现在使用队列解决不了任何问题。我错过了其他任何吸烟枪吗?同样,假设我删除了自定义队列,您为什么认为它会挂起等待运行的机会?我无法弄清楚我错过了什么(其他)...... 对主队列以外的任何内容进行 UI 更新实际上会使情况变得更糟。但是,如果您解决了这个问题并且它仍然挂起(完全死锁还是只是很慢?)那么肯定还有另一个问题潜伏在其他地方。我建议添加更多的日志记录语句,并更准确地缩小问题所在的范围。但是除了后台队列问题之外,您的代码 sn-p 中没有其他明显的问题。

以上是关于正确使用 Alamofire 队列的主要内容,如果未能解决你的问题,请参考以下文章

Alamofire 和并发操作队列

有没有办法配置 Alamofire 不将结果分派到主队列?

是否可以使用 Alamofire 创建多个单独的操作队列(或类似的东西)?

Alamofire如何维护请求顺序?

Alamofire 帖子正文格式不正确

如何使用 Alamofire 和 SwiftyJSON 正确解析 JSON