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

查看:161
本文介绍了后台使用单个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)\r\n")
            body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
            body.appendString("\(value)\r\n")
        }
    }
    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)\r\n")
        body.appendString("Content-Disposition: form-data; name=\"\(self.filePathKey)\"; filename=\"\(filename)\"\r\n")
        body.appendString("Content-Type: \(mimetype)\r\n\r\n")
        body.appendData(data!)
        body.appendString("\r\n")
        i += 1;
    }

    body.appendString("--\(boundary)--\r\n")
    //        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 in 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 = "\r\n"

    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天全站免登陆