后台使用单个 NSURLSession uploadTaskWithRequest 上传多张图片 [英] Background upload multiple images using single NSURLSession uploadTaskWithRequest

查看:50
本文介绍了后台使用单个 NSURLSession uploadTaskWithRequest 上传多张图片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用单个 uploadTaskWithRequest 方法在后台上传多张图片.在尝试以下代码时,后台会话不支持来自 NSData 的上传任务...请问如何实现这一点

I want to upload multiple images in background using a single uploadTaskWithRequest method. While trying the following code returns Upload tasks from NSData are not supported in background sessions...please how to achieve this

func createRequest (param : NSDictionary ,imagearray :NSMutableArray, strURL : String) -> NSURLRequest {

    let boundary = generateBoundaryString()

    let url = NSURL(string: strURL)
    let request = NSMutableURLRequest(URL: url!)

    request.setValue("multipart/form-data; boundary=(boundary)", forHTTPHeaderField: "Content-Type")
    request.HTTPMethod = "POST"
    request.HTTPBody = createBodyWithParameters(param, image_array:imagearray,boundary: boundary);

    return request
}

   func createBodyWithParameters(parameters: NSDictionary,image_array:NSMutableArray,boundary: String) -> NSData {
 let body = NSMutableData()         
for (key, value) in parameters {
      if(value is String || value is NSString){
            body.appendString("--(boundary)
")
            body.appendString("Content-Disposition: form-data; name="(key)"

")
            body.appendString("(value)
")
        }
    }
    var i = 0;
    for image in image_array {
        let filename = "image(i).jpg"
        let data = UIImagePNGRepresentation(image as! UIImage);
        let mimetype = "image/png"
        body.appendString("--(boundary)
")
        body.appendString("Content-Disposition: form-data; name="(self.filePathKey)"; filename="(filename)"
")
        body.appendString("Content-Type: (mimetype)

")
        body.appendData(data!)
        body.appendString("
")
        i += 1;
    }

    body.appendString("--(boundary)--
")
    //        NSLog("data %@",NSString(data: body, encoding: NSUTF8StringEncoding)!);
    return body
}

func postrequestwithformdata(requesturl:String,postparams:NSDictionary,postformadata:NSMutableArray,requestId:Int)  
{

    self.requestid = requestId;
    let requestformdata = self.createRequest(postparams, imagearray: postformadata, strURL: requesturl);
    let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(Contants.identifier)
    let session: NSURLSession = NSURLSession(configuration:configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue());
    let task: NSURLSessionUploadTask = session.uploadTaskWithRequest(requestformdata, fromData: requestformdata.HTTPBody!);
    task.resume();

}

推荐答案

要在后台会话中上传,必须先将数据保存到文件中.

To upload in a background session, the data must first saved to a file.

  1. 使用 writeToFile:options:.
  2. 调用 NSURLSession uploadTaskWithRequest:fromFile: 创建任务.请注意,请求中不能包含 HTTPBody 中的数据,否则上传会失败.
  3. URLSession:didCompleteWithError: 委托方法.
  1. Save the data to file using writeToFile:options:.
  2. Call NSURLSession uploadTaskWithRequest:fromFile: to create the task. Note that the request must not contain the data in the HTTPBody otherwise the upload will fail.
  3. Handle completion in the URLSession:didCompleteWithError: delegate method.

您可能还想处理应用在后台时完成的上传.

You may also want to handle uploads which complete while the app is in the background.

  1. 实现 application:handleEventsForBackgroundURLSession:completionHandler 在 AppDelegate 中.
  2. 使用提供的标识符创建一个 NSURLSession.
  3. 按照通常的上传响应委托方法(例如处理 URLSession:didCompleteWithError:)
  4. 调用 URLSessionDidFinishEventsForBackgroundURLSession 完成事件处理后.
  1. Implement application:handleEventsForBackgroundURLSession:completionHandler in the AppDelegate.
  2. Create an NSURLSession with the provided identifier.
  3. Respond to the delegate methods as per a usual upload (e.g. handle the response in URLSession:didCompleteWithError:)
  4. Call URLSessionDidFinishEventsForBackgroundURLSession when you have completed processing the event.

为了更容易管理,为每个上传任务创建一个 NSURLSession,每个任务都有一个唯一的标识符.

To make this easier to manage, create one NSURLSession per upload task, each with a unique identifier.

参考URL 会话编程指南了解实现细节.

AppDelegate 示例:

Example AppDelegate:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate {

    var window: UIWindow?

    typealias CompletionHandler = () -> Void

    var completionHandlers = [String: CompletionHandler]()

    var sessions = [String: NSURLSession]()


    func upload(request: NSURLRequest, data: NSData)
    {
        // Create a unique identifier for the session.
        let sessionIdentifier = NSUUID().UUIDString

        let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask).first!
        let fileURL = directoryURL.URLByAppendingPathComponent(sessionIdentifier)

        // Write data to cache file.
        data.writeToURL(fileURL, atomically: true);

        let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(sessionIdentifier)

        let session: NSURLSession = NSURLSession(
            configuration:configuration,
            delegate: self,
            delegateQueue: NSOperationQueue.mainQueue()
        )

        // Store the session, so that we don't recreate it if app resumes from suspend.
        sessions[sessionIdentifier] = session

        let task = session.uploadTaskWithRequest(request, fromFile: fileURL)

        task.resume()
    }

    // Called when the app becomes active, if an upload completed while the app was in the background.
    func application(application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: CompletionHandler) {

        let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(identifier)

        if sessions[identifier] == nil {

            let session = NSURLSession(
                configuration: configuration,
                delegate: self,
                delegateQueue: NSOperationQueue.mainQueue()
            )

            sessions[identifier] = session
        }

        completionHandlers[identifier] = completionHandler
    }

    func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {

        // Handle background session completion handlers.
        if let identifier = session.configuration.identifier {

            if let completionHandler = completionHandlers[identifier] {
                completionHandler()
                completionHandlers.removeValueForKey(identifier)
            }

            // Remove session
            sessions.removeValueForKey(identifier)
        }

        // Upload completed.
    }
}

要在单个请求中上传多个图像,必须首先将图像编码为 multipart/formdata MIME 类型,正如您所做的那样.不同之处在于整个 MIME 消息必须保存到单个文件中,该文件是上传到服务器的文件.

To upload multiple images in a single request, the images must first be encoded into the multipart/formdata MIME type, as you have done. The difference being that this entire MIME message must be saved to a single file, which is the file that is uploaded to the server.

这里是一个例子,展示了如何做到这一点.它通过将 MIME 部分直接序列化为文件来工作.您也可以在 NSData 中构建消息,尽管在处理大文件时可能会遇到内存限制.

Here is an example which shows how to do this. It works by serialising the MIME parts directly to a file. You could also build up the message in an NSData, although you risk running into memory limitations when handling large files.

func uploadImages(request: NSURLRequest, images: [UIImage]) {

    let uuid = NSUUID().UUIDString
    let boundary = String(count: 24, repeatedValue: "-" as Character) + uuid

    // Open the file
    let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask).first!

    let fileURL = directoryURL.URLByAppendingPathComponent(uuid)
    let filePath = fileURL.path!

    NSFileManager.defaultManager().createFileAtPath(filePath, contents: nil, attributes: nil)

    let file = NSFileHandle(forWritingAtPath: filePath)!


    // Write each image to a MIME part.
    let newline = "
"

    for (i, image) in images.enumerate() {

        let partName = "image-(i)"
        let partFilename = "(partName).png"
        let partMimeType = "image/png"
        let partData = UIImagePNGRepresentation(image)

        // Write boundary header
        var header = ""
        header += "--(boundary)" + newline
        header += "Content-Disposition: form-data; name="(partName)"; filename="(partFilename)"" + newline
        header += "Content-Type: (partMimeType)" + newline
        header += newline

        let headerData = header.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)

        print("")
        print("Writing header #(i)")
        print(header)

        print("Writing data")
        print("(partData!.length) Bytes")

        // Write data
        file.writeData(headerData!)
        file.writeData(partData!)
    }

    // Write boundary footer
    var footer = ""
    footer += newline
    footer += "--(boundary)--" + newline
    footer += newline

    print("")
    print("Writing footer")
    print(footer)

    let footerData = footer.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    file.writeData(footerData!)

    file.closeFile()

    // Add the content type for the request to multipart.
    let outputRequest = request.copy() as! NSMutableURLRequest

    let contentType = "multipart/form-data; boundary=(boundary)"
    outputRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")


    // Start uploading files.
    upload(outputRequest, fileURL: fileURL)
}

这篇关于后台使用单个 NSURLSession uploadTaskWithRequest 上传多张图片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆