2016-07-13 12 views
7

Chcę przesłać kilka zdjęć w tle przy użyciu jednej metody uploadTaskWithRequest. Starając następujący kod zwraca Dodaj zadania z NSData nie są obsługiwane w sesjach tle ... proszę, jak osiągnąć tenwysyłania tło wielu obrazów przy użyciu pojedynczego NSURLSession uploadTaskWithRequest

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

} 

Odpowiedz

10

Aby przesłać w sesji tle, dane muszą najpierw zapisać do pliku.

  1. Zapisz dane do pliku, używając writeToFile:options:.
  2. Zadzwoń do NSURLSession uploadTaskWithRequest:fromFile:, aby utworzyć zadanie. Pamiętaj, że żądanie nie może zawierać danych w pliku HTTPBody, ponieważ przesyłanie nie powiedzie się.
  3. Zakończenie obsługi w metodzie delegata URLSession:didCompleteWithError:.

Możesz również chcieć obsłużyć przesyłanie, które się zakończy, gdy aplikacja jest w tle.

  1. Implementacja application:handleEventsForBackgroundURLSession:completionHandler w AppDelegate.
  2. Utwórz NSURLSession z podanym identyfikatorem.
  3. odpowiedzieć na metodach delegatów jak za zwykłego przesyłania (np obsłużyć odpowiedź w URLSession:didCompleteWithError:)
  4. połączeń URLSessionDidFinishEventsForBackgroundURLSession po zakończeniu przetwarzania zdarzenia.

Aby ułatwić zarządzanie, utwórz jedno z nich: NSURLSession, z każdym unikalnym identyfikatorem.

Patrz URL Session Programming Guide do szczegółów implementacyjnych.

Przykład 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. 
    } 
} 

Aby przesłać kilka zdjęć w jednym wniosku, że obrazy muszą być najpierw zakodowane w wieloczęściowy/formdata typu MIME, jak to zrobić. Różnica polega na tym, że cały ten komunikat MIME musi być zapisany w jednym pliku, który jest plikiem przesłanym na serwer.

Oto przykład pokazujący, jak to zrobić. Działa poprzez szeregowanie części MIME bezpośrednio do pliku. Możesz również zbudować wiadomość w NSData, chociaż ryzykujesz, że uruchomisz ograniczenia pamięci podczas obsługi dużych plików.

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

ale mam wiele danych formularza obrazu, jak sobie z tym poradzić? –

+0

Zaktualizuj swoje pytanie, aby wyjaśnić, co próbujesz zrobić. Jak to jest obecnie, twoje pytanie nie wspomina nic o wielu obrazach. –

+0

Spójrz na [ten samouczek] (http://www.kaleidosblog.com/how-to-upload-images-using-swift-2-send-multipart-post-request), który pokazuje, jak używać kodowania MIME kodować wiele obrazów do pojedynczego żądania przesyłania. –

Powiązane problemy