In der vorherigen Anleitung habe ich Sie vorgestellt NSURLSession
. Ich habe über die Vorteile gesprochen NSURLConnection
und wie man es benutzt NSURLSession
Für einfache Aufgaben wie das Abrufen von Daten von einem Webdienst und das Herunterladen eines Bildes aus dem Web. In diesem Tutorial betrachten wir die Konfigurationsoptionen von NSURLSession
und wie Sie eine Download-Aufgabe abbrechen und fortsetzen können. Wir haben viel zu tun, also fangen wir an.
Wie wir im vorherigen Tutorial gesehen haben, eine Sitzung, eine Instanz von NSURLSession
, ist ein konfigurierbarer Container zum Einfügen von Netzwerkanforderungen. Die Konfiguration der Sitzung wird von einer Instanz von verwaltet NSURLSessionConfiguration
.
Ein Sitzungskonfigurationsobjekt ist nichts anderes als ein Wörterbuch mit Eigenschaften, das definiert, wie sich die Sitzung verhält, an die es gebunden ist. Eine Sitzung verfügt über ein Sitzungskonfigurationsobjekt, das die Cookie-, Sicherheits- und Cache-Richtlinien, die maximale Anzahl von Verbindungen zu einem Host, Ressourcen- und Netzwerk-Timeouts usw. festlegt. Dies ist eine wesentliche Verbesserung gegenüber NSURLConnection
, die auf ein globales Konfigurationsobjekt mit viel weniger Flexibilität angewiesen war.
Sobald eine Sitzung erstellt und konfiguriert wurde von NSURLSessionConfiguration
In diesem Fall kann die Konfiguration der Sitzung nicht geändert werden. Wenn Sie die Konfiguration einer Sitzung ändern müssen, müssen Sie eine neue Sitzung erstellen. Beachten Sie, dass Sie die Konfiguration einer Sitzung kopieren und ändern können. Die Änderungen haben jedoch keine Auswirkungen auf die Sitzung, aus der die Konfiguration kopiert wurde.
Das NSURLSessionConfiguration
class bietet drei Factory-Konstruktoren zum Instantiieren von Standardkonfigurationen, defaultSessionConfiguration
, ephemeralSessionConfiguration
, und backgroundSessionConfiguration
. Die erste Methode gibt eine Kopie von zurück Standardkonfiguration der Sitzung Objekt, das zu einer Sitzung führt, die sich ähnlich wie eine NSURLConnection
Objekt in seiner Standardkonfiguration. Ändern einer Sitzungskonfiguration über defaultSessionConfiguration
Die Factory-Methode ändert die Standardsitzungskonfiguration, von der sie eine Kopie ist, nicht.
Ein Sitzungskonfigurationsobjekt, das durch Aufrufen von erstellt wurde ephemeralSessionConfiguration
Die Factory-Methode stellt sicher, dass die resultierende Sitzung keinen permanenten Speicher für Cookies, Caches oder Anmeldeinformationen verwendet. Mit anderen Worten, Cookies, Caches und Anmeldeinformationen werden gespeichert. Ephemere Sitzungen sind daher ideal, wenn Sie privates Browsing implementieren müssen, was vor der Einführung von nicht möglich war NSURLSession
.
Das backgroundSessionConfiguration:
Die Factory-Methode erstellt ein Sitzungskonfigurationsobjekt, das das Hochladen und Herunterladen außerhalb des Prozesses ermöglicht. Die Upload- und Download-Tasks werden von einem Hintergrund-Daemon verwaltet und laufen auch dann weiter, wenn die Anwendung angehalten wird oder abstürzt. Wir werden später in dieser Serie mehr über Hintergrundsitzungen sprechen.
Wie wir im vorherigen Tutorial gesehen haben, ist das Erstellen eines Sitzungskonfigurationsobjekts einfach. In dem unten gezeigten Beispiel habe ich die verwendet defaultSessionConfiguration
Fabrikmethode zum Erstellen eines NSURLSessionConfiguration
Beispiel. Zum Konfigurieren eines Sitzungskonfigurationsobjekts müssen Sie nur die Eigenschaften ändern, wie im Beispiel gezeigt. Wir können dann das Sitzungskonfigurationsobjekt verwenden, um ein Sitzungsobjekt zu instanziieren. Das Sitzungsobjekt dient als Factory für Daten-, Upload- und Download-Aufgaben, wobei jede Aufgabe einer einzelnen Anforderung entspricht. Im folgenden Beispiel wird die iTunes-Such-API wie im vorherigen Lernprogramm abgefragt.
// Sitzungskonfiguration erstellen NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; // Sitzungskonfiguration konfigurieren [sessionConfiguration setAllowsCellularAccess: YES]; [sessionConfiguration setHTTPAdditionalHeaders: @ @ "Accept": @ "application / json"]; // Session erstellen NSURLSession * session = [NSURLSession sessionWithConfiguration: sessionConfiguration]; // Send Request NSURL * url = [NSURL URLWithString: @ "https://itunes.apple.com/search?term=apple&media=software"]; [[session dataTaskWithURL: URL completionHandler: ^ (NSData * -Daten, NSURLResponse * -Antwort, NSError * -Fehler) NSLog (@ "% @", [NSJSONSerialization JSONObjectWithData: Datenoptionen: 0 Fehler: nil]); ] fortsetzen];
Das Beispiel zeigt auch, wie einfach das Hinzufügen von benutzerdefinierten Kopfzeilen ist HTTPAdditionalHeaders
Eigenschaft des Sitzungskonfigurationsobjekts. Die Schönheit der NSURLSession
API ist, dass jede Anforderung, die die Sitzung durchläuft, durch das Konfigurationsobjekt der Sitzung konfiguriert wird. Das Hinzufügen von Authentifizierungs-Headern zu einem Satz von Anforderungen ist zum Beispiel ein Kinderspiel.
In der vorherigen Anleitung habe ich Ihnen gezeigt, wie Sie ein Bild mithilfe von herunterladen NSURLSession
API. Netzwerkverbindungen sind jedoch unzuverlässig und es kommt zu oft vor, dass ein Download aufgrund einer unübersichtlichen Netzwerkverbindung fehlschlägt. Glücklicherweise ist es nicht schwierig, einen Download fortzusetzen NSURLSession
API. Im nächsten Beispiel zeige ich Ihnen, wie Sie den Download eines Bildes abbrechen und fortsetzen können.
Bevor wir uns mit der Wiederaufnahme einer Download-Aufgabe näher beschäftigen, ist es wichtig, den Unterschied zwischen dem Abbrechen und dem Unterbrechen einer Download-Aufgabe zu verstehen. Es ist möglich, eine Download-Aufgabe anzuhalten und zu einem späteren Zeitpunkt fortzusetzen. Wenn Sie eine Download-Aufgabe abbrechen, wird die Aufgabe jedoch abgebrochen, und es ist nicht möglich, sie später wieder aufzunehmen. Es gibt jedoch eine Alternative. Es ist möglich, eine Download-Aufgabe durch Aufrufen abzubrechen cancelByProducingResumeData:
darauf Es akzeptiert einen Beendigungshandler, der einen Parameter akzeptiert NSData
Objekt, das verwendet wird, um den Download zu einem späteren Zeitpunkt durch Aufrufen wieder aufzunehmen downloadTaskWithResumeData:
oder downloadTaskWithResumeData: completionHandler:
auf einem Session-Objekt. Das NSData
Das Objekt enthält die erforderlichen Informationen, um die Download-Task dort fortzusetzen, wo sie aufgehört hat.
Öffnen Sie das Projekt, das wir im vorherigen Tutorial erstellt haben, oder laden Sie es hier herunter. Wir fangen damit an, der Benutzeroberfläche zwei Schaltflächen hinzuzufügen, eine zum Abbrechen des Downloads und eine zum Fortsetzen des Downloads. Erstellen Sie in der Header-Datei des View-Controllers einen Auslass und eine Aktion für jede Schaltfläche (siehe unten).
#einführen@interface MTViewController: UIViewController @property (schwach, nicht atomar) IBOutlet UIButton * cancelButton; @ property (schwach, nichtatomisch) IBOutlet UIButton * resumeButton; @ property (schwach, nichtatomisch) IBOutlet UIImageView * imageView; @ property (schwach, nicht atomar) IBOutlet UIProgressView * progressView; - (IBAction) cancel: (ID) Absender; - (IBAction) Lebenslauf: (ID) Absender; @Ende
Öffnen Sie das Haupt-Storyboard des Projekts und fügen Sie der Ansichts-Controller-Ansicht zwei Schaltflächen hinzu. Positionieren Sie die Tasten wie in der Abbildung unten gezeigt, und verbinden Sie jede Taste mit der entsprechenden Steckdose und Aktion.
Wir müssen ein wenig umgestalten, damit alles korrekt funktioniert. Öffnen MTViewController.m
und deklarieren Sie eine Instanzvariable und zwei Eigenschaften. Die Instanzvariable, Session
, enthält einen Verweis auf die Sitzung, die wir zum Herunterladen des Bildes verwenden.
#import "MTViewController.h" @interface MTViewController ()NSURLSession * _session; @ property (strong, nonatomic) NSURLSessionDownloadTask * downloadTask; @ property (strong, nonatomic) NSData * resumeData; @Ende
Wir müssen auch das umgestalten viewDidLoad
Methode, aber zuerst möchte ich eine Getter-Methode für die Sitzung implementieren. Die Implementierung ist ziemlich einfach, wie Sie unten sehen können. Wir erstellen ein Sitzungskonfigurationsobjekt mit dem defaultSessionConfiguration
Factory-Methode und instanziieren das Sitzungsobjekt damit. Der Ansichtscontroller dient als Delegierter der Sitzung.
- (NSURLSession *) session if (! _Session) // Sitzungskonfiguration erstellen NSURLSessionConfiguration * sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; // Sitzung erstellen _session = [NSURLSession sessionWithConfiguration: sessionConfiguration delegate: self delegateQueue: nil]; return _session;
Mit dem Session
Accessor implementiert, der viewDidLoad
Methode wird viel einfacher. Wir erstellen eine Download-Aufgabe wie in der vorherigen Übung und speichern einen Verweis auf die Aufgabe in downloadTask
. Wir weisen dann die Download-Aufgabe an fortsetzen
.
- (void) viewDidLoad [super viewDidLoad]; // Create Download Task self.downloadTask = [self.session downloadTaskWithURL: [NSURL URLWithString: @ "http://cdn.tutsplus.com/mobile/uploads/2014/01/5a3f1-sample.jpg"]]; // Download-Task fortsetzen [self.downloadTask-Lebenslauf];
Das stornieren:
Aktion enthält die Logik zum Abbrechen der gerade erstellten Download-Aufgabe. Ob downloadTask
ist nicht Null
, wir nennen cancelByProducingResumeData:
auf die aufgabe. Diese Methode akzeptiert einen Parameter, einen Beendigungsblock. Der Beendigungsblock benötigt auch einen Parameter, eine Instanz von NSData
. Ob resumeData
ist nicht Null
, Wir speichern einen Verweis auf das Datenobjekt in den View Controller resumeData
Eigentum.
Wenn ein Download nicht fortgesetzt werden kann, wird der Abschlussblock gesperrt resumeData
Parameter ist Null
. Nicht jeder Download ist wiederaufnehmbar, daher ist es wichtig zu prüfen, ob resumeData
ist gültig NSData
Objekt.
- (IBAction) cancel: (id) sender if (! Self.downloadTask) zurückkehren; // Hide-Schaltfläche ausblenden [self.cancelButton setHidden: YES]; [self.downloadTask cancelByProducingResumeData: ^ (NSData * resumeData) if (! resumeData) return; [self setResumeData: resumeData]; [self setDownloadTask: nil]; ];
Das Wiederaufnehmen der Download-Aufgabe nach dem Abbruch ist einfach. In dem fortsetzen:
Aktion prüfen wir, ob der View Controller resumeData
Eigenschaft ist gesetzt. Ob resumeData
ist gültig NSData
Objekt, sagen wir dem Session
Objekt anlegen, um eine neue Download-Aufgabe zu erstellen und die zu übergeben NSData
Objekt. Das ist alles Session
Das Objekt muss die Download-Aufgabe neu erstellen, die wir in der Datenbank abgebrochen haben stornieren:
Aktion. Wir weisen dann die Download-Aufgabe an fortsetzen
und setzen resumeData
zu Null
.
- (IBAction) resume: (id) sender if (! Self.resumeData) zurückkehren; // Hide Resume Button [self.resumeButton setHidden: YES]; // Create Download Task self.downloadTask = [self.session downloadTaskWithResumeData: self.resumeData]; // Download-Task fortsetzen [self.downloadTask-Lebenslauf]; // Bereinigung [self setResumeData: nil];
Erstellen Sie das Projekt und führen Sie die Anwendung im iOS-Simulator oder auf einem physischen Gerät aus. Der Download sollte automatisch starten. Tippen Sie auf die Schaltfläche "Abbrechen", um den Download abzubrechen, und tippen Sie auf die Schaltfläche "Resume", um den Download fortzusetzen.
Es gibt eine Reihe von Details, auf die wir achten müssen. Zunächst sollten die Schaltflächen nicht immer sichtbar sein. Wir verwenden die Schlüsselwertbeobachtung, um die Schaltflächen bei Bedarf ein- und auszublenden. Im viewDidLoad
, Blenden Sie die Schaltflächen aus und fügen Sie den View Controller als Beobachter für sich hinzu resumeData
und downloadTask
Schlüsselpfade.
- (void) viewDidLoad [super viewDidLoad]; // Observer hinzufügen [self addObserver: self forKeyPath: @ "resumeData" -Optionen: NSKeyValueObservingOptionNew context: NULL]; [self addObserver: self forKeyPath: @ "downloadTask" -Optionen: NSKeyValueObservingOption Neuer Kontext: NULL]; // Benutzeroberfläche einrichten [self.cancelButton setHidden: YES]; [self.resumeButton setHidden: YES]; // Create Download Task self.downloadTask = [self.session downloadTaskWithURL: [NSURL URLWithString: @ "http://cdn.tutsplus.com/mobile/uploads/2014/01/5a3f1-sample.jpg"]]; // Download-Task fortsetzen [self.downloadTask-Lebenslauf];
Im observValueForKeyPath: ofObject: change: context:
, Wenn nicht, wird der Abbrechen-Button ausgeblendet resumeData
ist Null
und wir verstecken den Resume-Button, wenn downloadTask
ist Null
. Erstellen Sie das Projekt und führen Sie die Anwendung noch einmal aus, um das Ergebnis anzuzeigen. Das ist besser. Recht?
- (void) observValueForKeyPath: (NSString *) keyPath ofObject: (id) Objektänderung: (NSDictionary *) Kontext ändern: (void *) Kontext if ([keyPath isEqualToString: @ "resumeData"]) ^ [self.resumeButton setHidden: (self.resumeData == nil)];); else if ([keyPath isEqualToString: @ "downloadTask"]) dispatch_async (dispatch_get_main_queue (), ^ [self.cancelButton setHidden: (self.downloadTask == nil)];);Wie George Yang in den Kommentaren betont, wissen wir nicht, ob
observValueForKeyPath: ofObject: change: context:
wird im Hauptthread aufgerufen. Es ist daher wichtig, die Benutzeroberfläche in einem GCD-Block (Grand Central Dispatch) zu aktualisieren, der in der Hauptwarteschlange aufgerufen wird. Es gibt einen wichtigen Aspekt von NSURLSession
über die ich noch nicht gesprochen habe, Sitzungsunfähigkeit. Die Sitzung enthält einen starken Verweis auf ihren Delegierten, was bedeutet, dass der Delegierte nicht freigegeben wird, solange die Sitzung aktiv ist. Um diesen Referenzzyklus zu unterbrechen, muss die Sitzung ungültig gemacht werden. Wenn eine Sitzung ungültig gemacht wird, werden aktive Aufgaben abgebrochen oder abgeschlossen, und der Delegat wird gesendet URLSession: didBecomeInvalidWithError:
Nachricht und die Sitzung gibt ihren Delegierten frei.
Es gibt mehrere Orte, an denen wir die Sitzung ungültig machen können. Da der View Controller nur ein Bild herunterlädt, kann die Sitzung nach Abschluss des Downloads für ungültig erklärt werden. Schauen Sie sich die aktualisierte Implementierung von an URLSession: downloadTask: didFinishDownloadingToURL:
. Die Abbrechen-Schaltfläche wird auch ausgeblendet, wenn der Download abgeschlossen ist.
- (void) URLSession: (NSURLSession *) Sitzung downloadTask: (NSURLSessionDownloadTask *) downloadTask didFinishDownloadingToURL: (NSURL *) location NSData * data = [NSData dataWithContentsOfURL: location]; dispatch_async (dispatch_get_main_queue (), ^ [self.cancelButton setHidden: YES]; [self.progressView setHidden: YES]; [self.imageView setImage: [UIImage imageWithData: data]];); // Sitzung ungültig machen [session finishTasksAndInvalidate];
Das Beispielprojekt, das wir in diesem Lernprogramm erstellt haben, ist eine vereinfachte Implementierung zum Abbrechen und Fortsetzen von Downloads. In Ihren Anwendungen muss möglicherweise das geschrieben werden resumeData
Objekt für spätere Verwendung auf Platte speichern, und es ist möglich, dass mehrere Download-Tasks gleichzeitig ausgeführt werden. Obwohl dies die Komplexität erhöht, bleiben die Grundprinzipien gleich. Stellen Sie sicher, dass Speicherverluste vermieden werden, indem Sie eine Sitzung, die Sie nicht mehr benötigen, immer für ungültig erklären.