Dieser Artikel ist eine Fortsetzung des Artikels
Interaktion mit dem Server über eine API in iOS unter Swift 3. Teil 1 und Aktualisierung eines
alten Artikels , der in Objective-C unter Swift 3 geschrieben wurde.
Kurze Theorie
GET Anfrage
GET ist die einfachste HTTP-Anforderungsmethode und wird vom Browser zum Laden von Webseiten verwendet. Es wird verwendet, um Inhalte anzufordern, die sich unter einer bestimmten URL befinden. Der Inhalt kann beispielsweise eine Webseite, ein Bild oder eine Audiodatei sein. Konventionell sind GET-Anforderungen schreibgeschützt und sollten gemäß dem W3C-Standard nicht in Vorgängen verwendet werden, die die Serverseite ändern. Beispielsweise verwenden wir keine GET-Anforderung, um ein Formular oder ein Foto zu senden, da diese Vorgänge einige Änderungen auf der Serverseite erfordern (in diesen Fällen wird POST verwendet).
POST-Anfrage
POST sendet Daten zur weiteren Verarbeitung an die URL. Parameter werden im Anforderungshauptteil im selben Format wie GET enthalten. Wenn wir beispielsweise ein Formular mit zwei Feldern, einem Namen und einem Alter, veröffentlichen möchten, senden wir im Anfragetext etwas Ähnliches wie name = Martin & age = 29.
Diese Methode zum Senden von Parametern wird häufig auf Webseiten verwendet. Die beliebtesten Fälle sind Formen. Wenn wir das Formular auf der Website ausfüllen und auf Senden klicken, lautet die Anfrage höchstwahrscheinlich POST.
In unserer Anwendung verwenden wir POST, um Witze zu bewerten. Wir senden Stimmen (oder +1 oder -1) an den Remote-Server.
POST-Anforderungsdaten können in verschiedenen Formaten strukturiert werden. Parameter werden normalerweise gemäß den Formulierungs-URL-Codierungsstandards (gemäß dem W3C-HTML-Standard) formatiert. Dies ist das Standardformat und wird in vielen Browsern häufig verwendet. Unsere Methode akzeptiert das Dictionary-Wörterbuch als Argument, aber wir können das Dictionary-Wörterbuch nicht über die HTTP-Verbindung senden, da es sich um einen internen Swift-Typ handelt. Um über eine HTTP-Verbindung weiterzuleiten, müssen wir eine erkennbare Darstellung des Wörterbuchs erstellen. Es ist wie mit einem Ausländer zu kommunizieren. Wir übersetzen unsere Botschaft in eine universelle Sprache und sie übersetzt von einer universellen Sprache in ihre Muttersprache. Die universelle Sprache in HTTP ist der W3C-Standard, unsere Sprache ist Swift, die Empfängersprache ist uns unbekannt.
Der W3C-Standard definiert Regeln, die definieren, was eine erkennbare Darstellung für jeden Fall bedeutet. In unserem Fall müssen wir die Parameter nach dem formular-url-codierten Teil des Standards präsentieren (z. B. param1 = var1 & param2 = var2).
Webview
Mit Programmiersprachen-Tools können wir Anforderungen an einen Remote-Server senden. Dies tun Browser, bevor sie eine Webseite anzeigen. Der Unterschied besteht nur im Inhalt der Antwort. Webseiten werden mit dem HTML-Standard formatiert, der eine Reihe von Regeln für die grafische Definition verschiedener Markup-Tags definiert. Diese Regeln scheinen einfach zu sein, aber das Anzeigen einer ganzen Seite nach dem W3C-Standard ist eine schwierige Aufgabe. Glücklicherweise verfügt iOS über eine integrierte UIWebView-Komponente, die die bekannte WebKit-Engine verwendet, HTML / CSS / JavaScript interpretiert und ganze Webseiten in einem UIView anzeigt.
Es gibt mehrere Fälle, in denen wir den Navigationsfluss steuern möchten. Zum Beispiel möchten wir wissen, wann bestimmte Inhalte oder eine bestimmte URL geladen werden.
Oder wir implementieren einen sicheren Browser für Kinder. Wir möchten den Benutzer daran hindern, Seiten zu laden, die bestimmten Kriterien wie Sex oder Drogen unterliegen. Für alle diese Arten der Anpassung erstellen wir eine Instanz einer Klasse, die das UIWebViewDelegate-Protokoll als UIWebView-Delegat implementiert. Wir können die folgenden Methoden implementieren:
webView:shouldStartLoadWithRequest:navigationType: webViewDidStartLoad: webViewDidFinishLoad: webView:didFailLoadWithError:
Mit der ersten Methode können wir den Navigationsfluss steuern, indem wir bestimmte Anforderungen zulassen oder blockieren. Die anderen drei Methoden sind Informationsereignisse (Methodennamen geben einen guten Überblick über das Ereignis).
Durchführung der Abstimmung per POST-Anfrage
Wir werden die
Dateien MainViewController.swift und
HTTPCommunication.swift hinzufügen und eine neue Datei
WebViewController.swift erstellen, in der wir unsere webView definieren.
Erstellen Sie zunächst eine neue WebViewController.swift-Datei und definieren Sie die WebViewController-Klasse darin:
WebViewController.swift import UIKit class WebViewController: UIViewController { } extension WebViewController { }
Jetzt implementieren wir die Funktionalität zum Erstellen von POST-Anforderungen in der Klasse, die für alle unsere HTTP-Operationen verantwortlich ist: HTTPCommunication-Klasse. Fügen Sie dazu in HTTPCommunication.swift eine neue postURL (_: params: CompletionHandler :) -Methode hinzu, die der vorherigen RetrieveURL (_: CompletionHandler :) -Methode ähnelt.
HTTPCommunication.swift class HTTPCommunication: NSObject { … func retrieveURL(_ url: URL, completionHandler: @escaping ((Data) -> Void)) { … }
Methodencode
func postURL(_ url: URL, params: [String: Int], completionHandler: @escaping ((Data) -> Void)) { // (K.1) self.completionHandler = completionHandler // (K.2) func postBody(params: [String: Int]) -> Data? { // (K.3) var paramsArr: [String] = [] for (key, value) in params { paramsArr.append("\(key)=\(value)") } let postBodyString: String = paramsArr.joined(separator: "&") let postBodyData: Data? = postBodyString.data(using: .utf8) return postBodyData } var request: URLRequest = URLRequest(url: url) // (K.4) request.httpMethod = "POST" request.httpBody = postBody(params: params) let session: URLSession = URLSession(configuration: .default, delegate: self, delegateQueue: nil) // (K.5) let task: URLSessionDownloadTask = session.downloadTask(with: request) task.resume() }
(K.1) Mit Closure arbeiten wir außerhalb dieser Funktion, daher bezeichnen wir sie mit @escaping.
(K.2) Wir speichern den übergebenen Abschluss in der Eigenschaft completeHandler.
(K.3) Wir schreiben eine Methode, die das Wörterbuch der übergebenen Parameter in eine Zeichenfolgenform konvertiert und diese Zeichenfolge dann in utf8-Codierung in den Datentyp codiert.
(K.4) Wir erstellen eine Anfrage mit der übergebenen URL und konfigurieren sie: Legen Sie POST als Methode fest und legen Sie unsere Parameter vom Datentyp mit utf8 als Anfragetext fest.
(K.5) Erstellen Sie abschließend eine Sitzung mit einer Standardkonfiguration und einem Delegaten wie uns. Und wir erstellen eine Aufgabe, um das Ergebnis dieser Anforderung in den temporären Speicher zu laden. Am Ende die Aufgabe auftauen.
Fügen wir nun die erforderliche Schnittstelle zu MainViewController.swift hinzu. Fügen Sie zwei Schaltflächen für die Abstimmung von voteUp und voteDown hinzu, wodurch die Bewertung des aktuellen Witzes erhöht bzw. verringert wird. Wir fügen auch die Schaltfläche "Chuck Who?" Hinzu, die wir im Abschnitt über die Webansicht mit Funktionen füllen werden.
Fügen Sie in MainViewController.swift den Initialisierungscode voteUpButton, voteDownButton und chuckWhoButton ein.
MainViewController.swift lazy var jokeLabel: UILabel! = … var jokeID: Int! lazy var activityView: UIActivityIndicatorView! = …
Initialisierungscode für Schaltflächen
lazy var voteUpButton: UIButton! = { // (L.1) let button: UIButton = UIButton(type: .system) // (L.2) button.setTitle("Vote Up", for: .normal) button.sizeToFit() button.addTarget(self, action: #selector(self.voteUp), for: .touchUpInside) // (L.3) self.view.addSubview(button) // (L.4) return button // (L.5) }() lazy var voteDownButton: UIButton! = { let button: UIButton = UIButton(type: .system) button.setTitle("Vote Down", for: .normal) button.sizeToFit() button.addTarget(self, action: #selector(self.voteDown), for: .touchUpInside) self.view.addSubview(button) return button }() lazy var chuckWhoButton: UIButton! = { let button: UIButton = UIButton(type: .system) button.setTitle("Chuck Who?", for: .normal) button.sizeToFit() button.addTarget(self, action: #selector(self.chuckWho), for: .touchUpInside) self.view.addSubview(button) return button }()
Der Initialisierungscode für alle drei Schaltflächen ist gleich.
(L.1) Wir deklarieren eine faule Variable und initialisieren sie mit einem Abschluss.
(L.2) Innerhalb des Abschlusses definieren wir eine lokale Variable für die Schaltfläche, einen Systemtyp, geben den Namen und die Größe an.
(L.3) Wir ordnen der Taste die entsprechende Aktion zu, wenn sie gedrückt wird.
(L.4) Zur Ansichtshierarchie hinzufügen.
(L.5) Und wir weisen diese lokale Variable unserer faulen Variablen zu.
Fügen Sie als Nächstes in MainViewController.swift den Methodencode für die Schaltflächen ein
MainViewController.swift class MainViewController: UIViewController { … func retrieveRandomJokes() { … }
Methodencode für Schaltflächen
func voteUp() { let http: HTTPCommunication = HTTPCommunication() // (M.1) let params: [String: Int] = ["joke_id": self.jokeID, "vote": 1] // (M.2) if let url = URL(string: "http://example.com/rater/vote") { // (M.3) http.postURL(url, params: params) { (data) in // (M.4) print("\(data). Voted Up") } } } func voteDown() { let http: HTTPCommunication = HTTPCommunication() let params: [String: Int] = ["joke_id": self.jokeID, "vote": -1] if let url = URL(string: "http://example.com/rater/vote") { http.postURL(url, params: params) { (data) in print("\(data). Voted Down") } } } func chuckWho() { }
Der Code der Methoden zum Auf- und Abstimmen ist der gleiche.
(M.1) Erstellen Sie ein Klassenobjekt für die Kommunikation mit dem Server.
(M.2) Wir erstellen ein Wörterbuch mit Parametern, das die ID des Witzes enthält, für den wir stimmen, und der tatsächliche Wert der Abstimmung beträgt +1 oder -1.
(M.3) Als Nächstes erhalten wir die URL sicher aus der Adressleiste unserer Trainingsdomäne
http://example.com/rater/vote.
(M.4) Und wir senden per POST eine Anfrage nach URL unserer Parameter. Drucken Sie auf der Konsole eine Zeile aus, die den Abschluss der Anforderung angibt.
Als Nächstes schreiben wir in MainViewController.swift den Code der configStackView-Methode unter Berücksichtigung der an der Benutzeroberfläche vorgenommenen Änderungen neu.
MainViewController.swift func configStackView() -> UIStackView { let innerStackView: UIStackView = UIStackView(arrangedSubviews: [self.voteUpButton, self.voteDownButton]) // (N.1) innerStackView.axis = .horizontal // (N.2) innerStackView.distribution = .fillEqually let mainStackView: UIStackView = UIStackView(arrangedSubviews: [self.jokeLabel, innerStackView, self.chuckWhoButton]) // (N.3) mainStackView.spacing = 50 // (N.4) mainStackView.axis = .vertical mainStackView.distribution = .fillEqually self.view.addSubview(mainStackView) // (N.5) return mainStackView }
(N.1) Erstellen Sie eine innerStackView mit zwei Schaltflächen zum Abstimmen.
(N.2) Wir legen die vertikale Achse frei; Die Verteilung ist die gleiche.
(N.3) Fügen Sie in der Haupt-MainStackView die innereStackView und die Schaltfläche über Chuck Norris zum Etikett aus dem letzten Teil hinzu.
(N.4) Konfigurieren Sie mainStackView.
(N.5) Fügen Sie mainStackView zur Ansichtshierarchie hinzu.
Wir starten unsere Anwendung und sehen die Schnittstelle wie in Abb. 1
Abb. 1 Die Oberfläche unserer Anwendung mit zusätzlichen Schaltflächen zum AbstimmenWir überprüfen, ob bei der Abstimmung für oder gegen einen Witz die folgenden Meldungen in der Konsole angezeigt werden:
345 bytes. Voted Up
oder
345 bytes. Voted Down
Dies zeigt eine erfolgreich abgeschlossene POST-Anforderung an den Server an.
Wir haben eine Scherzanwendung mit der icndb API und dem GET HTTP Verb geschrieben. Wir konnten diese Witze auf UIView zeigen und jeder Witz kann geschätzt werden. Diese Aktionen senden eine POST-Anforderung an den Remote-Server, wodurch unsere Schätzung gespeichert werden soll.
Verwenden von WebViews zum Anzeigen von Webseiten
Wir werden eine Webansicht hinzufügen, um die Wikipedia-Seite über Chuck Norris anzuzeigen. Sie wird auf Knopfdruck verwirrt.
Schreiben Sie in die Datei WebViewController.swift den folgenden Funktionsstub:
WebViewController.swift import UIKit class WebViewController: UIViewController { lazy var webView: UIWebView = { // (O.1) self.configWebView() }() lazy var toolbar: UIToolbar = { // (O.2) self.configToolbar() }() override func viewDidLoad() { super.viewDidLoad() } func back() { // (O.3) self.webView.goBack() } func forward() { self.webView.goForward() } } extension WebViewController { func configWebView() -> UIWebView { // (O.4) } func configToolbar() -> UIToolbar { // (O.5) } func configConstraints() { // (O.6) } }
(O.1) Wir erstellen Lazy-Variablen für webView
(O.2) und Symbolleiste.
(O.3) Wir erstellen Methoden zur Navigation in der Geschichte des Besuchs von Links vor und zurück.
(O.4) Wir fügen der Erweiterung webView-Initialisierungsmethoden hinzu
(O.5) und ToolBar
(O.6) und Einschränkungen für die Schnittstelle.
Jetzt malen wir den Code jeder Funktion:
func configWebView() -> UIWebView { let webView: UIWebView = UIWebView()
(P.1) Wir initialisieren die Webansicht und fügen die Ansicht der Hierarchie hinzu.
func configToolbar() -> UIToolbar { let toolbar: UIToolbar = UIToolbar(frame: CGRect.zero) // (Q.1) let backButton: UIBarButtonItem = UIBarButtonItem(title: , style: .plain, target: self, action: #selector(self.back)) // (Q.2) let forwardButton: UIBarButtonItem = UIBarButtonItem(title: , style: .plain, target: self, action: #selector(self.forward)) toolbar.setItems([backButton, forwardButton], animated: false) // (Q.3) toolbar.backgroundColor = UIColor.lightGray // (Q.4) self.view.addSubview(toolbar) return toolbar }
(Q.1) Erstellen Sie eine Symbolleiste mit einem Nullrahmen.
(Q.2) Wir erstellen zwei Schaltflächen zum Navigieren im Verlauf des Besuchs von Links. Mit den Namen "<" und ">" und den Aktionen, die an die entsprechende Methode in webView angehängt sind.
(Q.3) Fügen Sie diese Schaltflächen zur Symbolleiste hinzu.
(Q.4) Stellen Sie die Hintergrundfarbe wie die Navigationsleiste hellgrau ein. Und fügen Sie die Ansicht der Hierarchie hinzu.
func configConstraints() { self.webView.translatesAutoresizingMaskIntoConstraints = false // (R.1) NSLayoutConstraint.activate([ // (R.2) self.webView.topAnchor.constraint(equalTo: self.topLayoutGuide.topAnchor), self.webView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), self.webView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), self.webView.bottomAnchor.constraint(equalTo: self.toolbar.topAnchor) ]) self.toolbar.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ // (R.3) self.toolbar.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), self.toolbar.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), self.toolbar.bottomAnchor.constraint(equalTo: self.view.bottomAnchor), self.toolbar.heightAnchor.constraint(equalToConstant: 44.0) ]) }
(R.1) Deaktivieren Sie Autoresizing-Masken, damit sie nicht mit unseren Einschränkungen in Konflikt stehen
(R.2) Konfigurieren Sie für webView alle vier Seiten der Ansicht.
(R.3) Konfigurieren Sie für die Symbolleiste drei Seiten der Ansicht mit Ausnahme der Oberseite, stellen Sie jedoch zusätzlich die Höhe auf die Standardgröße 44,0 ein.
Schreiben Sie den Code ViewDidLoad () wie folgt neu:
override func viewDidLoad() { super.viewDidLoad() self.configConstraints()
(S.1) Rufen Sie die Einstellung von Einschränkungen auf.
(S.2) Holen Sie sich die URL sicher aus der Adressleiste der Wikipedia-Seite
en.wikipedia.org/wiki/Chuck_Norris(S.3) Wir erstellen eine Anfrage von der URL.
(S.4) Und wir führen die angegebene Anfrage in webView aus.
Wir kehren zum MainViewController zurück und füllen ihn mit der Methode zum Aufrufen von Informationen über Chuck Norris.
MainViewController.swift func chuckWho() { self.navigationController?.show(WebViewController(), sender: self)
(T.1) Wenn Sie auf diese Schaltfläche im Navigationscontroller-Stapel klicken, fügen Sie eine neue Instanz von webView ein.
Abb. 2 zeigt, wie webView in unserer Anwendung aussieht.
Abb. 2. Die endgültige Ansicht der von uns implementierten WebView