在获得所有响应后,Alamofire如何保证响应方法会被调用?

时间:2015-07-08 16:29:50

标签: ios grand-central-dispatch nsurlsession alamofire

最近我读了 Alamofire 的源代码,我真的很困惑 Alamofire 如何确保以正确的顺序调用响应方法。我希望有人(也许 matt 大声笑)可以帮助我。

示例,这样一个简单的GET请求

Alamofire.request(.GET, "https://api.github.com/users/octocat/received_events")

在分析了它的工作流程后,我发布了我的理解

  1. 创建 请求和基础 NSURLSession

     public func request(method: Method, URLString: URLStringConvertible, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL) -> Request {
       return Manager.sharedInstance.request(method, URLString, parameters: parameters, encoding: encoding)
     }
    

    此方法将创建请求:请求对象,该对象将包含基础 NSURLSessionDataTask 对象。 Manager.sharedInstance 已经设置了 NSURLSession 并将自己设置为该会话的委托。 Manager.sharedInstance 对象会将自定义对象 request.delegate 保存在自己的属性委托

  2. 创建这些对象后, Alamofire 会立即发送此请求。

    public func request(URLRequest: URLRequestConvertible) -> Request {
      var dataTask: NSURLSessionDataTask?
      dispatch_sync(queue) {
        dataTask = self.session.dataTaskWithRequest(URLRequest.URLRequest)
      }
    
      let request = Request(session: session, task: dataTask!)
      delegate[request.delegate.task] = request.delegate
    
      if startRequestsImmediately {
        request.resume()
      }
    
      return request
    } 
    
  3. 由于 Manager.sharedInstance 将自己设置为基础 NSURLSession 的委托,因此在收到数据时,将调用委托方法

    public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
        if dataTaskDidReceiveData != nil {
            dataTaskDidReceiveData!(session, dataTask, data)
        } else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
            delegate.URLSession(session, dataTask: dataTask, didReceiveData: data)
        }
    }
    
  4. 如果用户想要获得响应并执行相关操作,他将使用以下公共API

    // Here the request is a Request object
    self.request?.responseString { (request, response, body, error) in
        // Something do with the response
    }
    
  5. 让我们看看 responseString(_:completionHandler:)方法做了什么

    public func response(queue: dispatch_queue_t? = nil, serializer: Serializer, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {
      delegate.queue.addOperationWithBlock {
        let (responseObject: AnyObject?, serializationError: NSError?) = serializer(self.request, self.response, self.delegate.data)
    
        dispatch_async(queue ?? dispatch_get_main_queue()) {
            completionHandler(self.request, self.response, responseObject, self.delegate.error ?? serializationError)
        }
      }
    
      return self
    }
    
  6. 我的问题是如何在 3 之后保证 5 ,所以用户可以获得不属于它的所有响应,因为 self.response 此时将完全加载。

    是否因为NSURLSession的后台处理发生在同一个队列上 - delegate.queue ,这是在 Alamofire 中创建的:

    //class Request.TaskDelegate: NSObject, NSURLSessionTaskDelegate
    self.queue = {
      let operationQueue = NSOperationQueue()
      operationQueue.maxConcurrentOperationCount = 1
      operationQueue.suspended = true
    
      if operationQueue.respondsToSelector("qualityOfService") {
        operationQueue.qualityOfService = NSQualityOfService.Utility
      }
    
      return operationQueue
    }()
    

    我的理解是否正确,这是怎么发生的?如果你能指出我可以参考的地方,可能需要对 RunLoop NSURLSession的线程机制有所了解,谢谢你。

0 个答案:

没有答案