diff --git a/Source/Request.swift b/Source/Request.swift index b2b9c514b06936c6bae4a5123755cd210b1a9f11..f4224ffd5292a07be4854989e54361c37fe20951 100644 --- a/Source/Request.swift +++ b/Source/Request.swift @@ -134,56 +134,6 @@ public class Request { return self } - // MARK: - Response - - /** - A closure used by response handlers that takes a request, response, and data and returns a serialized object and any error that occured in the process. - */ - public typealias Serializer = (NSURLRequest, NSHTTPURLResponse?, NSData?) -> (AnyObject?, NSError?) - - /** - Creates a response serializer that returns the associated data as-is. - - :returns: A data response serializer. - */ - public class func responseDataSerializer() -> Serializer { - return { request, response, data in - return (data, nil) - } - } - - /** - Adds a handler to be called once the request has finished. - - :param: completionHandler The code to be executed once the request has finished. - - :returns: The request. - */ - public func response(completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self { - return response(serializer: Request.responseDataSerializer(), completionHandler: completionHandler) - } - - /** - Adds a handler to be called once the request has finished. - - :param: queue The queue on which the completion handler is dispatched. - :param: serializer The closure responsible for serializing the request, response, and data. - :param: completionHandler The code to be executed once the request has finished. - - :returns: The request. - */ - public func response(queue: dispatch_queue_t? = nil, serializer: Serializer, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self { - 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 - } - // MARK: - State /** diff --git a/Source/ResponseSerialization.swift b/Source/ResponseSerialization.swift index e030a7a87ace606975abcbe179ac1cb462211bc5..4ae703cadcfeb1017e56b80b749f4963dc39bb3a 100644 --- a/Source/ResponseSerialization.swift +++ b/Source/ResponseSerialization.swift @@ -22,9 +22,95 @@ import Foundation -// MARK: String +// MARK: - ResponseSerializer + +/** + The type in which all response serializers must conform to in order to serialize a response. +*/ +public protocol ResponseSerializer { + /// The type of serialized object to be created by this `ResponseSerializer`. + typealias SerializedObject + + /// A closure used by response handlers that takes a request, response, and data and returns a serialized object and any error that occured in the process. + var serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?) -> (SerializedObject?, NSError?) { get } +} + +/** + A generic `ResponseSerializer` used to serialize a request, response, and data into a serialized object. +*/ +public struct GenericResponseSerializer: ResponseSerializer { + /// The type of serialized object to be created by this `ResponseSerializer`. + public typealias SerializedObject = T + + /// A closure used by response handlers that takes a request, response, and data and returns a serialized object and any error that occured in the process. + public var serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?) -> (SerializedObject?, NSError?) +} + +// MARK: - Default + +extension Request { + + /** + Adds a handler to be called once the request has finished. + + :param: queue The queue on which the completion handler is dispatched. + :param: responseSerializer The response serializer responsible for serializing the request, response, and data. + :param: completionHandler The code to be executed once the request has finished. + + :returns: The request. + */ + public func response( + queue: dispatch_queue_t? = nil, + responseSerializer: T, + completionHandler: (NSURLRequest, NSHTTPURLResponse?, V?, NSError?) -> Void) + -> Self + { + self.delegate.queue.addOperationWithBlock { + let result: V? + let error: NSError? + + (result, error) = responseSerializer.serializeResponse(self.request, self.response, self.delegate.data) + + dispatch_async(queue ?? dispatch_get_main_queue()) { + completionHandler(self.request, self.response, result, self.delegate.error ?? error) + } + } + + return self + } +} + +// MARK: - Data + +extension Request { + + /** + Creates a response serializer that returns the associated data as-is. + + :returns: A data response serializer. + */ + public static func dataResponseSerializer() -> GenericResponseSerializer { + return GenericResponseSerializer { request, response, data in + return (data, nil) + } + } + + /** + Adds a handler to be called once the request has finished. + + :param: completionHandler The code to be executed once the request has finished. + + :returns: The request. + */ + public func response(completionHandler: (NSURLRequest, NSHTTPURLResponse?, NSData?, NSError?) -> Void) -> Self { + return response(responseSerializer: Request.dataResponseSerializer(), completionHandler: completionHandler) + } +} + +// MARK: - String extension Request { + /** Creates a response serializer that returns a string initialized from the response data with the specified string encoding. @@ -32,8 +118,8 @@ extension Request { :returns: A string response serializer. */ - public class func stringResponseSerializer(var encoding: NSStringEncoding? = nil) -> Serializer { - return { _, response, data in + public static func stringResponseSerializer(var encoding: NSStringEncoding? = nil) -> GenericResponseSerializer { + return GenericResponseSerializer { _, response, data in if data == nil || data?.length == 0 { return (nil, nil) } @@ -42,7 +128,7 @@ extension Request { encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding(encodingName)) } - let string = NSString(data: data!, encoding: encoding ?? NSISOLatin1StringEncoding) + let string = NSString(data: data!, encoding: encoding ?? NSISOLatin1StringEncoding) as? String return (string, nil) } @@ -56,16 +142,22 @@ extension Request { :returns: The request. */ - public func responseString(encoding: NSStringEncoding? = nil, completionHandler: (NSURLRequest, NSHTTPURLResponse?, String?, NSError?) -> Void) -> Self { - return response(serializer: Request.stringResponseSerializer(encoding: encoding)) { request, response, string, error in - completionHandler(request, response, string as? String, error) - } + public func responseString( + encoding: NSStringEncoding? = nil, + completionHandler: (NSURLRequest, NSHTTPURLResponse?, String?, NSError?) -> Void) + -> Self + { + return response( + responseSerializer: Request.stringResponseSerializer(encoding: encoding), + completionHandler: completionHandler + ) } } // MARK: - JSON extension Request { + /** Creates a response serializer that returns a JSON object constructed from the response data using `NSJSONSerialization` with the specified reading options. @@ -73,8 +165,8 @@ extension Request { :returns: A JSON object response serializer. */ - public class func JSONResponseSerializer(options: NSJSONReadingOptions = .AllowFragments) -> Serializer { - return { request, response, data in + public static func JSONResponseSerializer(options: NSJSONReadingOptions = .AllowFragments) -> GenericResponseSerializer { + return GenericResponseSerializer { request, response, data in if data == nil || data?.length == 0 { return (nil, nil) } @@ -94,16 +186,22 @@ extension Request { :returns: The request. */ - public func responseJSON(options: NSJSONReadingOptions = .AllowFragments, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self { - return response(serializer: Request.JSONResponseSerializer(options: options)) { request, response, JSON, error in - completionHandler(request, response, JSON, error) - } + public func responseJSON( + options: NSJSONReadingOptions = .AllowFragments, + completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) + -> Self + { + return response( + responseSerializer: Request.JSONResponseSerializer(options: options), + completionHandler: completionHandler + ) } } // MARK: - Property List extension Request { + /** Creates a response serializer that returns an object constructed from the response data using `NSPropertyListSerialization` with the specified reading options. @@ -111,14 +209,19 @@ extension Request { :returns: A property list object response serializer. */ - public class func propertyListResponseSerializer(options: NSPropertyListReadOptions = 0) -> Serializer { - return { request, response, data in + public static func propertyListResponseSerializer(options: NSPropertyListReadOptions = 0) -> GenericResponseSerializer { + return GenericResponseSerializer { request, response, data in if data == nil || data?.length == 0 { return (nil, nil) } var propertyListSerializationError: NSError? - let plist: AnyObject? = NSPropertyListSerialization.propertyListWithData(data!, options: options, format: nil, error: &propertyListSerializationError) + let plist: AnyObject? = NSPropertyListSerialization.propertyListWithData( + data!, + options: options, + format: nil, + error: &propertyListSerializationError + ) return (plist, propertyListSerializationError) } @@ -132,9 +235,14 @@ extension Request { :returns: The request. */ - public func responsePropertyList(options: NSPropertyListReadOptions = 0, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self { - return response(serializer: Request.propertyListResponseSerializer(options: options)) { request, response, plist, error in - completionHandler(request, response, plist, error) - } + public func responsePropertyList( + options: NSPropertyListReadOptions = 0, + completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) + -> Self + { + return response( + responseSerializer: Request.propertyListResponseSerializer(options: options), + completionHandler: completionHandler + ) } } diff --git a/Tests/AuthenticationTests.swift b/Tests/AuthenticationTests.swift index 01475d08d0485acd8681e920e2f58681b0e3181d..80b8bfd945cf163c3264644101bc5b88dcac2fc8 100644 --- a/Tests/AuthenticationTests.swift +++ b/Tests/AuthenticationTests.swift @@ -59,7 +59,7 @@ class BasicAuthenticationTestCase: AuthenticationTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -90,7 +90,7 @@ class BasicAuthenticationTestCase: AuthenticationTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -132,7 +132,7 @@ class HTTPDigestAuthenticationTestCase: AuthenticationTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -163,7 +163,7 @@ class HTTPDigestAuthenticationTestCase: AuthenticationTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When diff --git a/Tests/CacheTests.swift b/Tests/CacheTests.swift index ecd805baff6e3dd21f847e56408398a432a52414..af6cdd53f7f43c83b766d884f14d1df69dc680c5 100644 --- a/Tests/CacheTests.swift +++ b/Tests/CacheTests.swift @@ -182,7 +182,7 @@ class CacheTestCase: BaseTestCase { let request = self.manager.request(urlRequest) request.response( queue: queue, - serializer: Request.responseDataSerializer(), + responseSerializer: Request.dataResponseSerializer(), completionHandler: { _, response, _, _ in completion(request.request, response) } diff --git a/Tests/DownloadTests.swift b/Tests/DownloadTests.swift index 0908daa85175c895a50180f753a3ab89d150fe03..8869d6c9eac36f4528400872ee98d4c813cc949e 100644 --- a/Tests/DownloadTests.swift +++ b/Tests/DownloadTests.swift @@ -154,7 +154,7 @@ class DownloadResponseTestCase: BaseTestCase { var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = [] var responseRequest: NSURLRequest? var responseResponse: NSHTTPURLResponse? - var responseData: AnyObject? + var responseData: NSData? var responseError: NSError? // When diff --git a/Tests/RequestTests.swift b/Tests/RequestTests.swift index 84c73e8fc481521deec9f72ac7f3104c75187379..cba8173f86a6702ff9e696c902237ecd57980e5f 100644 --- a/Tests/RequestTests.swift +++ b/Tests/RequestTests.swift @@ -80,18 +80,18 @@ class RequestResponseTestCase: BaseTestCase { func testRequestResponse() { // Given let URLString = "http://httpbin.org/get" - let serializer = Alamofire.Request.stringResponseSerializer(encoding: NSUTF8StringEncoding) + let serializer = Request.stringResponseSerializer(encoding: NSUTF8StringEncoding) let expectation = expectationWithDescription("GET request should succeed: \(URLString)") var request: NSURLRequest? var response: NSHTTPURLResponse? - var string: AnyObject? + var string: String? var error: NSError? // When Alamofire.request(.GET, URLString, parameters: ["foo": "bar"]) - .response(serializer: serializer) { responseRequest, responseResponse, responseString, responseError in + .response(responseSerializer: serializer) { responseRequest, responseResponse, responseString, responseError in request = responseRequest response = responseResponse string = responseString @@ -120,7 +120,7 @@ class RequestResponseTestCase: BaseTestCase { var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = [] var responseRequest: NSURLRequest? var responseResponse: NSHTTPURLResponse? - var responseData: AnyObject? + var responseData: NSData? var responseError: NSError? // When @@ -189,7 +189,7 @@ class RequestResponseTestCase: BaseTestCase { var responseRequest: NSURLRequest? var responseResponse: NSHTTPURLResponse? - var responseData: AnyObject? + var responseData: NSData? var responseError: NSError? // When diff --git a/Tests/ResponseTests.swift b/Tests/ResponseTests.swift index 356af6bbfd980a114450ed8e5efb45c283a75085..81376954435fc9a03d6bef679f1ea352843544e9 100644 --- a/Tests/ResponseTests.swift +++ b/Tests/ResponseTests.swift @@ -110,7 +110,7 @@ class RedirectResponseTestCase: BaseTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -145,7 +145,7 @@ class RedirectResponseTestCase: BaseTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -185,7 +185,7 @@ class RedirectResponseTestCase: BaseTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -225,7 +225,7 @@ class RedirectResponseTestCase: BaseTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -267,7 +267,7 @@ class RedirectResponseTestCase: BaseTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When diff --git a/Tests/URLProtocolTests.swift b/Tests/URLProtocolTests.swift index adf3d5966a639ba976243821209e2fa96f2aa90f..9fb589b70c43d5c1e61fd2740e140aa7b411b4bf 100644 --- a/Tests/URLProtocolTests.swift +++ b/Tests/URLProtocolTests.swift @@ -137,15 +137,15 @@ class URLProtocolTestCase: BaseTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var string: AnyObject? + var data: NSData? var error: NSError? // When Alamofire.request(URLRequest) - .response { responseRequest, responseResponse, responseString, responseError in + .response { responseRequest, responseResponse, responseData, responseError in request = responseRequest response = responseResponse - string = responseString + data = responseData error = responseError expectation.fulfill() @@ -156,7 +156,7 @@ class URLProtocolTestCase: BaseTestCase { // Then XCTAssertNotNil(request, "request should not be nil") XCTAssertNotNil(response, "response should not be nil") - XCTAssertNotNil(string, "string should not be nil") + XCTAssertNotNil(data, "data should not be nil") XCTAssertNil(error, "error should be nil") if let headers = response?.allHeaderFields as? [String: String] { diff --git a/Tests/UploadTests.swift b/Tests/UploadTests.swift index 46d7459ec55ad48529ecb58543ee363026c23d62..6ad2717d5c5e72b3459c26f34ec1a2aea17088e8 100644 --- a/Tests/UploadTests.swift +++ b/Tests/UploadTests.swift @@ -186,7 +186,7 @@ class UploadDataTestCase: BaseTestCase { var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = [] var responseRequest: NSURLRequest? var responseResponse: NSHTTPURLResponse? - var responseData: AnyObject? + var responseData: NSData? var responseError: NSError? // When @@ -259,7 +259,7 @@ class UploadMultipartFormDataTestCase: BaseTestCase { var formData: MultipartFormData? var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -316,7 +316,7 @@ class UploadMultipartFormDataTestCase: BaseTestCase { var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When @@ -593,7 +593,7 @@ class UploadMultipartFormDataTestCase: BaseTestCase { var progressValues: [(completedUnitCount: Int64, totalUnitCount: Int64)] = [] var request: NSURLRequest? var response: NSHTTPURLResponse? - var data: AnyObject? + var data: NSData? var error: NSError? // When