ResponseSerialization.swift 11.4 KB
Newer Older
1
// ResponseSerialization.swift
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//
// Copyright (c) 2014–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import Foundation

25 26 27 28 29 30 31 32 33
// 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

34 35 36 37
    /**
        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.
    */
38 39 40 41 42 43 44 45 46 47
    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

48 49 50 51
    /**
        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.
    */
52
    public var serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?) -> (SerializedObject?, NSError?)
53 54 55 56

    /**
        Initializes the `GenericResponseSerializer` instance with the given serialize response closure.

57
        - parameter serializeResponse: The closure used to serialize the response.
58

59
        - returns: The new generic response serializer instance.
60 61 62 63
    */
    public init(serializeResponse: (NSURLRequest?, NSHTTPURLResponse?, NSData?) -> (SerializedObject?, NSError?)) {
        self.serializeResponse = serializeResponse
    }
64 65 66
}

// MARK: - Default
67 68

extension Request {
69 70 71 72

    /**
        Adds a handler to be called once the request has finished.

73 74 75 76
        - parameter queue:              The queue on which the completion handler is dispatched.
        - parameter responseSerializer: The response serializer responsible for serializing the request, response, 
                                        and data.
        - parameter completionHandler:  The code to be executed once the request has finished.
77

78
        - returns: The request.
79 80 81 82
    */
    public func response<T: ResponseSerializer, V where T.SerializedObject == V>(
        queue: dispatch_queue_t? = nil,
        responseSerializer: T,
83
        completionHandler: (NSURLRequest?, NSHTTPURLResponse?, V?, NSError?) -> Void)
84 85
        -> Self
    {
86
        delegate.queue.addOperationWithBlock {
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
            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.

108
        - returns: A data response serializer.
109 110 111 112 113 114 115 116 117 118
    */
    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.

119
        - parameter completionHandler: The code to be executed once the request has finished.
120

121
        - returns: The request.
122
    */
123
    public func response(completionHandler: (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> Void) -> Self {
124
        return response(responseSerializer: Request.dataResponseSerializer(), completionHandler: completionHandler)
125 126 127 128
    }
}

// MARK: - String
129 130

extension Request {
131

132
    /**
133 134
        Creates a response serializer that returns a string initialized from the response data with the specified 
        string encoding.
135

136 137
        - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server 
                              response, falling back to the default HTTP default character set, ISO-8859-1.
138

139
        - returns: A string response serializer.
140
    */
141 142 143 144
    public static func stringResponseSerializer(
        var encoding encoding: NSStringEncoding? = nil)
        -> GenericResponseSerializer<String>
    {
145
        return GenericResponseSerializer { _, response, data in
146
            guard let data = data where data.length > 0 else {
147 148
                return (nil, nil)
            }
149

150
            if let encodingName = response?.textEncodingName where encoding == nil {
151 152 153
                encoding = CFStringConvertEncodingToNSStringEncoding(
                    CFStringConvertIANACharSetNameToEncoding(encodingName)
                )
154
            }
155

156
            let string = NSString(data: data, encoding: encoding ?? NSISOLatin1StringEncoding) as? String
157

158 159 160
            return (string, nil)
        }
    }
161

162 163
    /**
        Adds a handler to be called once the request has finished.
164

165 166 167 168 169 170 171
        - parameter encoding:          The string encoding. If `nil`, the string encoding will be determined from the 
                                       server response, falling back to the default HTTP default character set, 
                                       ISO-8859-1.
        - parameter completionHandler: A closure to be executed once the request has finished. The closure takes 4 
                                       arguments: the URL request, the URL response, if one was received, the string, 
                                       if one could be created from the URL response and data, and any error produced 
                                       while creating the string.
172

173
        - returns: The request.
174
    */
175
    public func responseString(
176 177
        encoding encoding: NSStringEncoding? = nil,
        completionHandler: (NSURLRequest?, NSHTTPURLResponse?, String?, NSError?) -> Void)
178 179 180 181
        -> Self
    {
        return response(
            responseSerializer: Request.stringResponseSerializer(encoding: encoding),
182
            completionHandler: completionHandler
183
        )
184 185 186
    }
}

187
// MARK: - JSON
188 189

extension Request {
190

191
    /**
192 193
        Creates a response serializer that returns a JSON object constructed from the response data using 
        `NSJSONSerialization` with the specified reading options.
194

195
        - parameter options: The JSON serialization reading options. `.AllowFragments` by default.
196

197
        - returns: A JSON object response serializer.
198
    */
199 200 201 202
    public static func JSONResponseSerializer(
        options options: NSJSONReadingOptions = .AllowFragments)
        -> GenericResponseSerializer<AnyObject>
    {
203
        return GenericResponseSerializer { request, response, data in
204
            guard let data = data where data.length > 0 else {
205 206
                return (nil, nil)
            }
207

208
            var JSON: AnyObject?
209
            var serializationError: NSError?
210 211

            do {
212
                JSON = try NSJSONSerialization.JSONObjectWithData(data, options: options)
213
            } catch {
214
                serializationError = error as NSError
215
            }
216

217 218 219
            return (JSON, serializationError)
        }
    }
220

221 222
    /**
        Adds a handler to be called once the request has finished.
223

224 225 226 227 228
        - parameter options:           The JSON serialization reading options. `.AllowFragments` by default.
        - parameter completionHandler: A closure to be executed once the request has finished. The closure takes 4 
                                       arguments: the URL request, the URL response, if one was received, the JSON 
                                       object, if one could be created from the URL response and data, and any error 
                                       produced while creating the JSON object.
229

230
        - returns: The request.
231
    */
232
    public func responseJSON(
233 234
        options options: NSJSONReadingOptions = .AllowFragments,
        completionHandler: (NSURLRequest?, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void)
235 236 237 238
        -> Self
    {
        return response(
            responseSerializer: Request.JSONResponseSerializer(options: options),
239
            completionHandler: completionHandler
240
        )
241 242 243
    }
}

244
// MARK: - Property List
245 246

extension Request {
247

248
    /**
249 250
        Creates a response serializer that returns an object constructed from the response data using 
        `NSPropertyListSerialization` with the specified reading options.
251

252
        - parameter options: The property list reading options. `0` by default.
253

254
        - returns: A property list object response serializer.
255
    */
256 257 258 259
    public static func propertyListResponseSerializer(
        options options: NSPropertyListReadOptions = NSPropertyListReadOptions())
        -> GenericResponseSerializer<AnyObject>
    {
260
        return GenericResponseSerializer { request, response, data in
261
            guard let data = data where data.length > 0 else {
262 263
                return (nil, nil)
            }
264

265
            var plist: AnyObject?
266
            var propertyListSerializationError: NSError?
267 268

            do {
269
                plist = try NSPropertyListSerialization.propertyListWithData(data, options: options, format: nil)
270
            } catch {
271
                propertyListSerializationError = error as NSError
272
            }
273

274 275 276
            return (plist, propertyListSerializationError)
        }
    }
277

278 279
    /**
        Adds a handler to be called once the request has finished.
280

281 282 283 284 285
        - parameter options:           The property list reading options. `0` by default.
        - parameter completionHandler: A closure to be executed once the request has finished. The closure takes 4 
                                       arguments: the URL request, the URL response, if one was received, the property 
                                       list, if one could be created from the URL response and data, and any error 
                                       produced while creating the property list.
286

287
        - returns: The request.
288
    */
289
    public func responsePropertyList(
290 291
        options options: NSPropertyListReadOptions = NSPropertyListReadOptions(),
        completionHandler: (NSURLRequest?, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void)
292 293 294 295
        -> Self
    {
        return response(
            responseSerializer: Request.propertyListResponseSerializer(options: options),
296
            completionHandler: completionHandler
297
        )
298 299
    }
}