瀏覽代碼

Merge pull request #593 from Alamofire/feature/response_generics

Christian Noon 10 年之前
父節點
當前提交
5c586a331d

+ 0 - 50
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
 
     /**

+ 129 - 21
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<T>: 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<T: ResponseSerializer, V where T.SerializedObject == V>(
+        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<NSData> {
+        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<String> {
+        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<AnyObject> {
+        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<AnyObject> {
+        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
+        )
     }
 }

+ 4 - 4
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

+ 1 - 1
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)
             }

+ 1 - 1
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

+ 5 - 5
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

+ 5 - 5
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

+ 4 - 4
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] {

+ 4 - 4
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