背景使用单个NSURLSession uploadTaskWithRequest上传多个图像
我想要使用一个uploadTaskWithRequest
方法在后台上传多个图像。 当尝试下面的代码返回从NSData的上传任务不支持后台会议…请如何实现这一点
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(); }
要在后台会话中上传,必须先将数据保存到文件中。
- 使用writeToFile:选项将数据保存到文件。
- 调用NSURLSession uploadTaskWithRequest:fromFile:创build任务。 请注意,该请求不得包含
HTTPBody
的数据,否则上传将失败。 - 在URLSession:didCompleteWithError: delegate方法中处理完成。
您也可能想要处理在应用程序处于后台时完成的上传。
- 在AppDelegate中实现应用程序:handleEventsForBackgroundURLSession:completionHandler 。
- 用提供的标识符创build一个NSURLSession。
- 根据通常的上传响应委托方法(例如处理URLSession中的响应:didCompleteWithError:)
- 当您完成处理事件时调用URLSessionDidFinishEventsForBackgroundURLSession 。
为了便于pipe理, NSURLSession
为每个上传任务创build一个NSURLSession
,每个都有唯一的标识符。
有关实施细节,请参阅URL会话编程指南 。
示例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 MIMEtypes,如上所述。 不同的是,这整个MIME邮件必须保存到一个文件,这是上传到服务器的文件。
这里是一个例子,显示如何做到这一点。 它通过将MIME部分直接序列化到文件来工作。 您也可以在NSData中构build消息,但是在处理大文件时可能会遇到内存限制。
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) }