El background carga varias imágenes usando solo NSURLSession uploadTaskWithRequest

Quiero upload varias imágenes en segundo plano utilizando un único método uploadTaskWithRequest . Al probar el siguiente código, las tareas de carga de NSData no se admiten en sesiones de background … por favor, cómo lograr esto

 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(); } 

Para cargar en una session en segundo plano, los datos primero deben savese en un file.

  1. Guarde los datos en el file utilizando writeToFile: options:.
  2. Llame a NSURLSession uploadTaskWithRequest: fromFile: para crear la tarea. Tenga en count que la request no debe contener los datos en el HTTPBody contrario, la carga fallará.
  3. Manejar la finalización en el método URLSession: didCompleteWithError: delegate.

También puede manejar cargas que se completen mientras la aplicación se encuentra en segundo plano.

  1. Implementar la aplicación: handleEventsForBackgroundURLSession: completionHandler en AppDelegate.
  2. Cree una session NSURL con el identificador proporcionado.
  3. Responda a los methods delegates de acuerdo con una carga habitual (por ejemplo, maneje la respuesta en URLSession: didCompleteWithError:)
  4. Llame a URLSessionDidFinishEventsForBackgroundURLSession cuando haya completado el procesamiento del evento.

Para que esto sea más fácil de administrar, cree una tarea NSURLSession por carga, cada una con un identificador único.

Consulte la Guía de progtwigción de la session de URL para get detalles sobre la implementación.

Ejemplo de 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. } } 

Para cargar varias imágenes en una única request, las imágenes primero deben codificarse en el tipo MIME multipart / formdata, como ya hizo. La diferencia es que todo este post MIME debe savese en un único file, que es el file que se carga en el server.

Aquí hay un ejemplo que muestra cómo hacer esto. Funciona serializando las partes MIME directamente en un file. También podría generar el post en un NSData, aunque corre el riesgo de encontrarse con limitaciones de memory al manejar files de gran tamaño.

 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) }