Manager

作者: 幸运的小强本人 | 来源:发表于2016-02-29 18:45 被阅读138次

/***
Responsible for creating and managing 'Request' objects, as well as their underlying 'NSURLSession'.
*/

public class Manager {
    // MARK: - Properties
    /**
        A shared instance of 'Manager', used by top-
        level Alamofire request for any ad hoc request
    */
    public static let sharedInstance = {
        ket configuration = NSURLSessionConfiguration, defaultSessionConfiguration()
        configuration.HTTPAdditionalHeaders = Manager.defaultHTTPHeaders

        return Manager(configuration: configuration)
    }()

    /**
        Creates default values for the "Accept-Encoding" ...
    */
    public static let defaultHTTPHeaders: [String: String] = {

    }()

    let queue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL)

    // The underlying session
    public let session: NSURLSession

    // The session delegate handling all the task and 
    // session delegate callbacks.
    public let delegate: SessionDelegate

    // Whether to start requests immediately after 
    // being constructed. 'true' by default
    public var startRequestsImmediately: Bool = true

    /**

    */
    public var backgroundCompletionHandler: (() -> Void)?

    // MARK: - Lifecycle
    public init(configuration: NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: SessionDelegate = SessionDelegate(), serverTrustPolicyManager: ServerTrustPolicyManager? = nil) {
        self.delegate = delegate
        self.session = NSURLSession(configuration: configuration, delegate:delegate, delegateQueue:nil)

        commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
    }

    public init?(session: NSURLSession, delegate:SessionDelegate, serverTrustPolicyManager: ServerTrustPolicyManager? = nil) {
        self.delegate = delegate
        self.session = session

        guard delegate === session.delegate else {
            return nil
        }

        commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
    }

    private func commonInit(serverTrustPolicyManager serverTrustPolicyManager: ServerTrustPolicyManager?) {
        session.serverTrustPolicyManager = serverTrustPolicyManager

        delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
            guard let strongSelf = self else { return }
            dispatch_async(dispatch_get_main_queue()) {
                strongSelf.backgroundCompletionHandler?()
            }
        }
    }

    deinit {
        session.invalidateAndCancel()
    }

    /**
        Creates a request fro the specified method, URL 
        string, parameters, parameter encoding and 
        headers.
    */
    public func request(method: Method, _ URLString: URLStringConvertible, parameter: ParameterEncoding = .URL, headers: [String: String]? = nil) ->Request {
        let mutableURLRequest = URLRequest(method, URLString, headers: headers)
        let encodedURLRequest = encoding.encode(mutableURLRequest, parameters:parameters).0

        return request(encodedURLRequest)
    }

    /**
        Creates a request for the specified URL request
    */
    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
    }

    // MARK: - SessionDelegate
    /**
        Responsible for handling all delegate callbacks for the underlying session.
    */
    public final class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
        private var subdelegates: [Int: Request.TaskDelegate] = [:]
        private let subdelegateQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT)

        subscript(task: NSURLSessionTask) -> Request.TaskDelegate? {
            get {
                var subdelegate: Request.TaskDelegate?
                dispatch_sync(subdelegateQueue) { subdelegate = self.subdelegates[task.taskIdentifier] }

                return subdelegate
            }

            set {
                dispatch_barrier_async(subdelegateQueue) { self.subdelegates[task.taskIdentifier] = newValue }
            }
        }

        /**
            Initializes the `SessionDelegate` instance.
            - returns: The new `SessionDelegate` instance.
        */
        public override init() {
            super.init()
        }

        // MARK: - NSURLSessionDelegate
        // MARK: Override Closures
        /// Overrides default behavior for NSURLSessionDelegate method `URLSession:didBecomeInvalidWithError:`.
        public var sessionDidBecomeInvalidWithError: ((NSURLSession, NSError?) -> Void)?

        /// Overrides default behavior for NSURLSessionDelegate method `URLSession:didReceiveChallenge:completionHandler:`.
        public var sessionDidReceiveChallenge: ((NSURLSession, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?

        /// Overrides default behavior for NSURLSessionDelegate method `URLSessionDidFinishEventsForBackgroundURLSession:`.
        public var sessionDidFinishEventsForBackgroundURLSession: ((NSURLSession) -> Void)?

        // MARK: Delegate Methods

        /**
            Tells the delegate that the session has been invalidated.
            - parameter session: The session object that was invalidated.
            - parameter error:   The error that caused invalidation, or nil if the invalidation was explicit.
        */
        public func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) {
            sessionDidBecomeInvalidWithError?(session, error)
        }  

        /**
            Requests credentials from the delegate in response to a session-level authentication request from the remote server.
            - parameter session:           The session containing the task that requested authentication.
            - parameter challenge:         An object that contains the request for authentication.
            - parameter completionHandler: A handler that your delegate method must call providing the disposition and credential.
         */
        public func URLSession(
              session: NSURLSession,
              didReceiveChallenge challenge: NSURLAuthenticationChallenge,
              completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)) {
                  var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
                  var credential: NSURLCredential?

                  if let sessionDidReceiveChallenge = sessionDidReceiveChallenge {
                      (disposition, credential) = sessionDidReceiveChallenge(session, challenge)
                  } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
                      let host = challenge.protectionSpace.host

                      if let serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicyForHost(host),
                        serverTrust = challenge.protectionSpace.serverTrust {
                          if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
                            disposition = .UseCredential
                            credential = NSURLCredential(forTrust: serverTrust)
                          } else {
                              disposition = .CancelAuthenticationChallenge
                          }
                  }
              }

              completionHandler(disposition, credential)
        }

        /**
            Tells the delegate that all messages enqueued for a session have been delivered.
        */
        public func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) {
            sessionDidFinishEventsForBackgroundURLSession?(session)
        }

        // MARK: - NSURLSessionTaskDelegate
        // MARK: Override Closures

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:`.
        public var taskWillPerformHTTPRedirection: ((NSURLSession, NSURLSessionTask, NSHTTPURLResponse, NSURLRequest) -> NSURLRequest?)?

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didReceiveChallenge:completionHandler:`.
        public var taskDidReceiveChallenge: ((NSURLSession, NSURLSessionTask, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:session:task:needNewBodyStream:`.
        public var taskNeedNewBodyStream: ((NSURLSession, NSURLSessionTask) -> NSInputStream!)?

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`.
        public var taskDidSendBodyData: ((NSURLSession, NSURLSessionTask, Int64, Int64, Int64) -> Void)?

        /// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:didCompleteWithError:`.
        public var taskDidComplete: ((NSURLSession, NSURLSessionTask, NSError?) -> Void)?

        // MARK: Delegate Methods
        public func URLSession(
            session: NSURLSession,
            task: NSURLSessionTask,
            willPerformHTTPRedirection response: NSHTTPURLResponse,
            newRequest request: NSURLRequest,
            completionHandler: ((NSURLRequest?) -> Void)) {
              var redirectRequest: NSURLRequest? = request

              if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {
                  redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)
              }

              completionHandler(redirectRequest)
        }

        /**
            Requests credentials from the delegate in response to an authentication request from the remote server.
        */
        public func URLSession(
            session: NSURLSession,
            task: NSURLSessionTask,
            didReceiveChallenge challenge: NSURLAuthenticationChallenge,
            completionHandler: ((NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)) {
              if let taskDidReceiveChallenge = taskDidReceiveChallenge {
                completionHandler(taskDidReceiveChallenge(session, task, challenge))
              } else if let delegate = self[task] {
                  delegate.URLSession(session,task: task,didReceiveChallenge: challenge,completionHandler: completionHandler )
              } else {
                  URLSession(session, didReceiveChallenge: challenge, completionHandler: completionHandler)
              }
         }

         /**
            Tells the delegate when a task requires a new request body stream to send to the remote server.
         */
        public func URLSession(session: NSURLSession, task: NSURLSessionTask, needNewBodyStream completionHandler: ((NSInputStream?) -> Void)) {
            if let taskNeedNewBodyStream = taskNeedNewBodyStream {
                completionHandler(taskNeedNewBodyStream(session, task))
            } else if let delegate = self[task] {
                delegate.URLSession(session, task: task, needNewBodyStream: completionHandler)
            }
        }

        /**
            Periodically informs the delegate of the progress of sending body content to the server.
        */
        public func URLSession(session: NSURLSession,task: NSURLSessionTask,didSendBodyData bytesSent: Int64,totalBytesSent: Int64,totalBytesExpectedToSend: Int64) {
            if let taskDidSendBodyData = taskDidSendBodyData {
                taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)
            } else if let delegate = self[task] as? Request.UploadTaskDelegate {
                delegate.URLSession(session,task: task,didSendBodyData: bytesSent,totalBytesSent: totalBytesSent,totalBytesExpectedToSend:totalBytesExpectedToSend)
            }
         }

        /**
            Tells the delegate that the task finished transferring data.
        */
        public func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
            if let taskDidComplete = taskDidComplete {
                taskDidComplete(session, task, error)
            } else if let delegate = self[task] {
                delegate.URLSession(session, task: task, didCompleteWithError: error)
            }
            NSNotificationCenter.defaultCenter().postNotificationName(Notifications.Task.DidComplete, object: task)
            self[task] = nil
        }

        // MARK: - NSURLSessionDataDelegate
        // MARK: Override Closures

        /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didReceiveResponse:completionHandler:`.
        public var dataTaskDidReceiveResponse: ((NSURLSession, NSURLSessionDataTask, NSURLResponse) -> NSURLSessionResponseDisposition)?

        /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didBecomeDownloadTask:`.
        public var dataTaskDidBecomeDownloadTask: ((NSURLSession, NSURLSessionDataTask, NSURLSessionDownloadTask) -> Void)?

        /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:didReceiveData:`.
        public var dataTaskDidReceiveData: ((NSURLSession, NSURLSessionDataTask, NSData) -> Void)?

        /// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:willCacheResponse:completionHandler:`.
        public var dataTaskWillCacheResponse: ((NSURLSession, NSURLSessionDataTask, NSCachedURLResponse) -> NSCachedURLResponse!)?

        // MARK: Delegate Methods

        /**
            Tells the delegate that the data task received the initial reply (headers) from the server.
        */
        public func URLSession(session: NSURLSession,dataTask: NSURLSessionDataTask,didReceiveResponse response: NSURLResponse,completionHandler: ((NSURLSessionResponseDisposition) -> Void)) {
            var disposition: NSURLSessionResponseDisposition = .Allow

            if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {
                disposition = dataTaskDidReceiveResponse(session, dataTask, response)
            }

            completionHandler(disposition)
        }

        /**
            Tells the delegate that the data task was changed to a download task.
        */
        public func URLSession(session: NSURLSession,dataTask: NSURLSessionDataTask,didBecomeDownloadTask downloadTask:NSURLSessionDownloadTask) {
            if let dataTaskDidBecomeDownloadTask = dataTaskDidBecomeDownloadTask {
                dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask)
            } else {
                let downloadDelegate = Request.DownloadTaskDelegate(task: downloadTask)
                self[downloadTask] = downloadDelegate
            }
        }

        /**
            Tells the delegate that the data task has received some of the expected data.
        */
        public func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
            if let dataTaskDidReceiveData = dataTaskDidReceiveData {
                dataTaskDidReceiveData(session, dataTask, data)
            } else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
                delegate.URLSession(session, dataTask: dataTask, didReceiveData: data)
            }
        }

        /**
            Asks the delegate whether the data (or upload) task should store the response in the cache.
        */
        public func URLSession(session: NSURLSession,dataTask: NSURLSessionDataTask,willCacheResponse proposedResponse: NSCachedURLResponse,completionHandler: ((NSCachedURLResponse?) -> Void)) {
            if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {
                completionHandler(dataTaskWillCacheResponse(session, dataTask, proposedResponse))
            } else if let delegate = self[dataTask] as? Request.DataTaskDelegate {
                delegate.URLSession(session,dataTask: dataTask,willCacheResponse: proposedResponse,completionHandler: completionHandler)
            } else {
                completionHandler(proposedResponse)
            }
        }

        // MARK: - NSURLSessionDownloadDelegate
        // MARK: Override Closures
        /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didFinishDownloadingToURL:`.
    public var downloadTaskDidFinishDownloadingToURL: ((NSURLSession, NSURLSessionDownloadTask, NSURL) -> Void)?

        /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:`.
        public var downloadTaskDidWriteData: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64, Int64) -> Void)?

        /// Overrides default behavior for NSURLSessionDownloadDelegate method `URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:`.
        public var downloadTaskDidResumeAtOffset: ((NSURLSession, NSURLSessionDownloadTask, Int64, Int64) -> Void)?

        // MARK: Delegate Methods

        /**
            Tells the delegate that a download task has finished downloading.
        */
        public func URLSession(session: NSURLSession,downloadTask: NSURLSessionDownloadTask,didFinishDownloadingToURL location: NSURL) {
            if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL {
                downloadTaskDidFinishDownloadingToURL(session, downloadTask, location)
            } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
                delegate.URLSession(session, downloadTask: downloadTask, didFinishDownloadingToURL: location)
            }
        }

        /**
            Periodically informs the delegate about the download’s progress.
        */
        public func URLSession(session: NSURLSession,downloadTask: NSURLSessionDownloadTask,didWriteData bytesWritten: Int64,totalBytesWritten: Int64,totalBytesExpectedToWrite: Int64) {
            if let downloadTaskDidWriteData = downloadTaskDidWriteData {
                downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
            } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
                delegate.URLSession(session,downloadTask: downloadTask,didWriteData: bytesWritten,totalBytesWritten: totalBytesWritten,totalBytesExpectedToWrite: totalBytesExpectedToWrite )
            }
        }

        /**
            Tells the delegate that the download task has resumed downloading
        */
        public func URLSession(session: NSURLSession,downloadTask: NSURLSessionDownloadTask,didResumeAtOffset fileOffset: Int64,expectedTotalBytes: Int64) {
            if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset {
                downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes)
            } else if let delegate = self[downloadTask] as? Request.DownloadTaskDelegate {
                delegate.URLSession(session,downloadTask: downloadTask,didResumeAtOffset: fileOffset,expectedTotalBytes: expectedTotalBytes)
            }
        }

        // MARK: - NSURLSessionStreamDelegate
        var _streamTaskReadClosed: Any?
        var _streamTaskWriteClosed: Any?
        var _streamTaskBetterRouteDiscovered: Any?
        var _streamTaskDidBecomeInputStream: Any?

        // MARK: - NSObject
        public override func respondsToSelector(selector: Selector) -> Bool {
            switch selector {
              case "URLSession:didBecomeInvalidWithError:":
                return sessionDidBecomeInvalidWithError != nil
              case "URLSession:didReceiveChallenge:completionHandler:":
                return sessionDidReceiveChallenge != nil
              case "URLSessionDidFinishEventsForBackgroundURLSession:":
                return sessionDidFinishEventsForBackgroundURLSession != nil
              case "URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:":
                return taskWillPerformHTTPRedirection != nil
              case "URLSession:dataTask:didReceiveResponse:completionHandler:":
                return dataTaskDidReceiveResponse != nil
              default:
                return self.dynamicType.instancesRespondToSelector(selector)
            }
        }
    }
}

相关文章

网友评论

      本文标题:Manager

      本文链接:https://www.haomeiwen.com/subject/yougkttx.html