/***
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)
}
}
}
}
网友评论