Aby przesłać w sesji tle, dane muszą najpierw zapisać do pliku.
- Zapisz dane do pliku, używając writeToFile:options:.
- 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ę.
- 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.
- Implementacja application:handleEventsForBackgroundURLSession:completionHandler w AppDelegate.
- Utwórz NSURLSession z podanym identyfikatorem.
- odpowiedzieć na metodach delegatów jak za zwykłego przesyłania (np obsłużyć odpowiedź w URLSession:didCompleteWithError:)
- 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)
}
ale mam wiele danych formularza obrazu, jak sobie z tym poradzić? –
Zaktualizuj swoje pytanie, aby wyjaśnić, co próbujesz zrobić. Jak to jest obecnie, twoje pytanie nie wspomina nic o wielu obrazach. –
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. –