Forráskód Böngészése

Added support in the Manager for uploading MultipartFormData.

Christian Noon 10 éve
szülő
commit
138db4a425
2 módosított fájl, 195 hozzáadás és 0 törlés
  1. 51 0
      Source/Alamofire.swift
  2. 144 0
      Source/Upload.swift

+ 51 - 0
Source/Alamofire.swift

@@ -206,6 +206,57 @@ public func upload(URLRequest: URLRequestConvertible, stream: NSInputStream) ->
     return Manager.sharedInstance.upload(URLRequest, stream: stream)
 }
 
+// MARK: MultipartFormData
+
+/**
+    Creates an upload request using the shared manager instance for the specified method and URL string.
+
+    :param: method                  The HTTP method.
+    :param: URLString               The URL string.
+    :param: multipartFormData       The closure used to append body parts to the `MultipartFormData`.
+    :param: encodingMemoryThreshold The encoding memory threshold in bytes. `MultipartFormDataEncodingMemoryThreshold` 
+                                    by default.
+    :param: encodingCompletion      The closure called when the `MultipartFormData` encoding is complete.
+*/
+public func upload(
+    method: Method,
+    #URLString: URLStringConvertible,
+    #multipartFormData: MultipartFormData -> Void,
+    encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
+    #encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?)
+{
+    return Manager.sharedInstance.upload(
+        method,
+        URLString,
+        multipartFormData: multipartFormData,
+        encodingMemoryThreshold: encodingMemoryThreshold,
+        encodingCompletion: encodingCompletion
+    )
+}
+
+/**
+    Creates an upload request using the shared manager instance for the specified method and URL string.
+
+    :param: URLRequest              The URL request.
+    :param: multipartFormData       The closure used to append body parts to the `MultipartFormData`.
+    :param: encodingMemoryThreshold The encoding memory threshold in bytes. `MultipartFormDataEncodingMemoryThreshold`
+                                    by default.
+    :param: encodingCompletion      The closure called when the `MultipartFormData` encoding is complete.
+*/
+public func upload(
+    URLRequest: URLRequestConvertible,
+    #multipartFormData: MultipartFormData -> Void,
+    encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
+    #encodingCompletion: (Manager.MultipartFormDataEncodingResult -> Void)?)
+{
+    return Manager.sharedInstance.upload(
+        URLRequest,
+        multipartFormData: multipartFormData,
+        encodingMemoryThreshold: encodingMemoryThreshold,
+        encodingCompletion: encodingCompletion
+    )
+}
+
 // MARK: - Download Methods
 
 // MARK: URL Request

+ 144 - 0
Source/Upload.swift

@@ -156,6 +156,150 @@ extension Manager {
     public func upload(method: Method, _ URLString: URLStringConvertible, stream: NSInputStream) -> Request {
         return upload(URLRequest(method, URLString), stream: stream)
     }
+
+    // MARK: MultipartFormData
+
+    /// Default memory threshold used when encoding `MultipartFormData`.
+    public static let MultipartFormDataEncodingMemoryThreshold: UInt64 = 10 * 1024 * 1024
+
+    /**
+        Defines whether the `MultipartFormData` encoding was successful and contains result of the encoding as 
+        associated values.
+
+        - Success: Represents a successful `MultipartFormData` encoding and contains the new `Request` along with 
+                   streaming information.
+        - Failure: Used to represent a failure in the `MultipartFormData` encoding and also contains the encoding 
+                   error.
+    */
+    public enum MultipartFormDataEncodingResult {
+        case Success(request: Request, streamingFromDisk: Bool, streamFileURL: NSURL?)
+        case Failure(NSError)
+    }
+
+    /**
+        Encodes the `MultipartFormData` and creates a request to upload the result to the specified URL request.
+
+        It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative 
+        payload is small, encoding the data in-memory and directly uploading to a server is the by far the most 
+        efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to 
+        be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory 
+        footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be 
+        used for larger payloads such as video content.
+
+        The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory 
+        or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
+        encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk 
+        during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding 
+        technique was used.
+
+        If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+
+        :param: method                  The HTTP method.
+        :param: URLString               The URL string.
+        :param: multipartFormData       The closure used to append body parts to the `MultipartFormData`.
+        :param: encodingMemoryThreshold The encoding memory threshold in bytes. `MultipartFormDataEncodingMemoryThreshold`
+                                        by default.
+        :param: encodingCompletion      The closure called when the `MultipartFormData` encoding is complete.
+    */
+    public func upload(
+        method: Method,
+        _ URLString: URLStringConvertible,
+        multipartFormData: MultipartFormData -> Void,
+        encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
+        encodingCompletion: (MultipartFormDataEncodingResult -> Void)?)
+    {
+        let urlRequest = URLRequest(method, URLString)
+
+        return upload(
+            urlRequest,
+            multipartFormData: multipartFormData,
+            encodingMemoryThreshold: encodingMemoryThreshold,
+            encodingCompletion: encodingCompletion
+        )
+    }
+
+    /**
+        Encodes the `MultipartFormData` and creates a request to upload the result to the specified URL request.
+
+        It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative
+        payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
+        efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
+        be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
+        footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
+        used for larger payloads such as video content.
+
+        The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
+        or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
+        encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
+        during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
+        technique was used.
+
+        If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+
+        :param: URLRequest              The URL request.
+        :param: multipartFormData       The closure used to append body parts to the `MultipartFormData`.
+        :param: encodingMemoryThreshold The encoding memory threshold in bytes. `MultipartFormDataEncodingMemoryThreshold`
+                                        by default.
+        :param: encodingCompletion      The closure called when the `MultipartFormData` encoding is complete.
+    */
+    public func upload(
+        URLRequest: URLRequestConvertible,
+        multipartFormData: MultipartFormData -> Void,
+        encodingMemoryThreshold: UInt64 = Manager.MultipartFormDataEncodingMemoryThreshold,
+        encodingCompletion: (MultipartFormDataEncodingResult -> Void)?)
+    {
+        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
+            let formData = MultipartFormData()
+            multipartFormData(formData)
+
+            if formData.contentLength < encodingMemoryThreshold {
+                let encodingResult = formData.encode()
+
+                dispatch_async(dispatch_get_main_queue()) {
+                    switch encodingResult {
+                    case .Success(let data):
+                        let encodingResult = MultipartFormDataEncodingResult.Success(
+                            request: self.upload(URLRequest, data: data),
+                            streamingFromDisk: false,
+                            streamFileURL: nil
+                        )
+                        encodingCompletion?(encodingResult)
+                    case .Failure(let error):
+                        encodingCompletion?(.Failure(error))
+                    }
+                }
+            } else {
+                let fileManager = NSFileManager.defaultManager()
+                let tempDirectoryURL = NSURL(fileURLWithPath: NSTemporaryDirectory())!
+                let directoryURL = tempDirectoryURL.URLByAppendingPathComponent("com.alamofire.manager/multipart.form.data")
+                let fileName = NSUUID().UUIDString
+                let fileURL = directoryURL.URLByAppendingPathComponent(fileName)
+
+                var error: NSError?
+
+                if fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil, error: &error) {
+                    formData.writeEncodedDataToDisk(fileURL) { error in
+                        dispatch_async(dispatch_get_main_queue()) {
+                            if let error = error {
+                                encodingCompletion?(.Failure(error))
+                            } else {
+                                let encodingResult = MultipartFormDataEncodingResult.Success(
+                                    request: self.upload(URLRequest, file: fileURL),
+                                    streamingFromDisk: true,
+                                    streamFileURL: fileURL
+                                )
+                                encodingCompletion?(encodingResult)
+                            }
+                        }
+                    }
+                } else {
+                    dispatch_async(dispatch_get_main_queue()) {
+                        encodingCompletion?(.Failure(error!))
+                    }
+                }
+            }
+        }
+    }
 }
 
 // MARK: -