Wie mache ich eine HTTP-Anfrage in Swift?


371

Ich habe die Programmiersprache Swift von Apple in iBooks gelesen , kann aber nicht herausfinden, wie eine HTTP-Anfrage (so etwas wie cURL) in Swift gestellt wird. Muss ich Obj-C-Klassen importieren oder muss ich nur Standardbibliotheken importieren? Oder ist es nicht möglich, eine HTTP-Anfrage basierend auf nativem Swift-Code zu stellen?


2
Verwenden Sie URLSession (GET, POST, DELETE METHODS): stackoverflow.com/a/48306950/6898523
MAhipal Singh

Antworten:


550

Sie können verwendet werden URL, URLRequestund URLSessionoder , NSURLConnectionwie Sie normalerweise in Objective-C tun würden. Beachten Sie, dass für iOS 7.0 und höher URLSessionbevorzugt wird.

Verwenden von URLSession

Initialisieren Sie ein URLObjekt und ein URLSessionDataTaskvon URLSession. Führen Sie dann die Aufgabe mit aus resume().

let url = URL(string: "http://www.stackoverflow.com")!

let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
    guard let data = data else { return }
    print(String(data: data, encoding: .utf8)!)
}

task.resume()

Verwenden von NSURLConnection

Initialisieren Sie zunächst a URLund a URLRequest:

let url = URL(string: "http://www.stackoverflow.com")!
var request = URLRequest(url: url)
request.httpMethod = "POST" 

Anschließend können Sie die Anforderung asynchron laden mit:

NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue.main) {(response, data, error) in
    guard let data = data else { return }
    print(String(data: data, encoding: .utf8)!)
}

Oder Sie können ein initialisieren NSURLConnection:

let connection = NSURLConnection(request: request, delegate:nil, startImmediately: true)

Stellen Sie einfach sicher, dass Ihr Delegat auf etwas anderes als eingestellt ist, nilund verwenden Sie die Delegatenmethoden, um mit der Antwort und den empfangenen Daten zu arbeiten.

Weitere Informationen finden Sie in der Dokumentation zum NSURLConnectionDataDelegateProtokoll

Testen auf einem Xcode-Spielplatz

Wenn Sie diesen Code auf einem Xcode-Spielplatz ausprobieren möchten, fügen Sie ihn import PlaygroundSupportIhrem Spielplatz sowie den folgenden Aufruf hinzu:

PlaygroundPage.current.needsIndefiniteExecution = true

Auf diese Weise können Sie asynchronen Code auf Spielplätzen verwenden.


2
Verschwenden Sie Ihre Zeit nicht mit iOS 8 Beta 2 auf einem Spielplatz, da XCPlayground nicht unterstützt wird. Es gibt eine clevere und hässliche Möglichkeit zu warten, wenn Sie einen Hack versuchen möchten: stackoverflow.com/a/24058337/700206
whitneyland

7
Wie senden Sie POST-Daten mit NSURLSession?
Fernando Santiago

2
Dieses Beispiel schlägt bei 6.1 fehl: test.swift: 5: 57: error: Wert des optionalen Typs 'NSURL?' nicht ausgepackt; Wolltest du '!' oder '?'? let task = NSURLSession.sharedSession (). dataTaskWithURL (url) {(Daten, Antwort, Fehler) in
mcuadros

2
Das Hinzufügen eines Ausrufezeichens behebt die Fehlermeldung von @mcuadros ... .dataTaskWithURL (url!)
Sean McClory

3
Können Sie bitte die Codefragmente reparieren? Hier ist, was ab Swift 4print(String(data: data!, encoding: String.Encoding.utf8))
Nate

101

Überprüfen Sie die folgenden Codes:

1. SynchonousRequest

Swift 1.2

    let urlPath: String = "YOUR_URL_HERE"
    var url: NSURL = NSURL(string: urlPath)!
    var request1: NSURLRequest = NSURLRequest(URL: url)
    var response: AutoreleasingUnsafeMutablePointer<NSURLResponse?>=nil
    var dataVal: NSData =  NSURLConnection.sendSynchronousRequest(request1, returningResponse: response, error:nil)!
    var err: NSError
    println(response)
    var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataVal, options: NSJSONReadingOptions.MutableContainers, error: &err) as? NSDictionary
    println("Synchronous\(jsonResult)")

Swift 2.0 +

let urlPath: String = "YOUR_URL_HERE"
    let url: NSURL = NSURL(string: urlPath)!
    let request1: NSURLRequest = NSURLRequest(URL: url)
    let response: AutoreleasingUnsafeMutablePointer<NSURLResponse?>=nil


    do{

        let dataVal = try NSURLConnection.sendSynchronousRequest(request1, returningResponse: response)

            print(response)
            do {
                if let jsonResult = try NSJSONSerialization.JSONObjectWithData(dataVal, options: []) as? NSDictionary {
                    print("Synchronous\(jsonResult)")
                }
            } catch let error as NSError {
                print(error.localizedDescription)
            }



    }catch let error as NSError
    {
         print(error.localizedDescription)
    }

2. AsynchonousRequest

Swift 1.2

let urlPath: String = "YOUR_URL_HERE"
    var url: NSURL = NSURL(string: urlPath)!
    var request1: NSURLRequest = NSURLRequest(URL: url)
    let queue:NSOperationQueue = NSOperationQueue()
    NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
        var err: NSError
        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        println("Asynchronous\(jsonResult)")
       })

Swift 2.0 +

let urlPath: String = "YOUR_URL_HERE"
    let url: NSURL = NSURL(string: urlPath)!
    let request1: NSURLRequest = NSURLRequest(URL: url)
    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in

        do {
            if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
                print("ASynchronous\(jsonResult)")
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }


    })

3. Wie gewohnt URL-Verbindung

Swift 1.2

    var dataVal = NSMutableData()
    let urlPath: String = "YOUR URL HERE"
    var url: NSURL = NSURL(string: urlPath)!
    var request: NSURLRequest = NSURLRequest(URL: url)
    var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: true)!
    connection.start()

Dann

 func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
    self.dataVal?.appendData(data)
}


func connectionDidFinishLoading(connection: NSURLConnection!)
{
    var error: NSErrorPointer=nil

    var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataVal!, options: NSJSONReadingOptions.MutableContainers, error: error) as NSDictionary

    println(jsonResult)



}

Swift 2.0 +

   var dataVal = NSMutableData()
    let urlPath: String = "YOUR URL HERE"
    var url: NSURL = NSURL(string: urlPath)!
    var request: NSURLRequest = NSURLRequest(URL: url)
    var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: true)!
    connection.start()

Dann

func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
    dataVal.appendData(data)
}


func connectionDidFinishLoading(connection: NSURLConnection!)
{

    do {
        if let jsonResult = try NSJSONSerialization.JSONObjectWithData(dataVal, options: []) as? NSDictionary {
            print(jsonResult)
        }
    } catch let error as NSError {
        print(error.localizedDescription)
    }

}

4. Asynchrone POST-Anfrage

Swift 1.2

    let urlPath: String = "YOUR URL HERE"
    var url: NSURL = NSURL(string: urlPath)!
    var request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)

    request1.HTTPMethod = "POST"
     var stringPost="deviceToken=123456" // Key and Value

    let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)

    request1.timeoutInterval = 60
    request1.HTTPBody=data
    request1.HTTPShouldHandleCookies=false

    let queue:NSOperationQueue = NSOperationQueue()

     NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in


        var err: NSError

        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        println("AsSynchronous\(jsonResult)")


        })

Swift 2.0 +

let urlPath: String = "YOUR URL HERE"
    let url: NSURL = NSURL(string: urlPath)!
    let request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)

    request1.HTTPMethod = "POST"
    let stringPost="deviceToken=123456" // Key and Value

    let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)

    request1.timeoutInterval = 60
    request1.HTTPBody=data
    request1.HTTPShouldHandleCookies=false

    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in

        do {
            if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
                print("ASynchronous\(jsonResult)")
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }


    })

5. Asynchrone GET-Anfrage

Swift 1.2

    let urlPath: String = "YOUR URL HERE"
    var url: NSURL = NSURL(string: urlPath)!
    var request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)

    request1.HTTPMethod = "GET"
    request1.timeoutInterval = 60
    let queue:NSOperationQueue = NSOperationQueue()

     NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in


        var err: NSError

        var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
        println("AsSynchronous\(jsonResult)")


        })

Swift 2.0 +

let urlPath: String = "YOUR URL HERE"
    let url: NSURL = NSURL(string: urlPath)!
    let request1: NSMutableURLRequest = NSMutableURLRequest(URL: url)

    request1.HTTPMethod = "GET"
    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request1, queue: queue, completionHandler:{ (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in

        do {
            if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? NSDictionary {
                print("ASynchronous\(jsonResult)")
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }


    })

6. Bild (Datei) hochladen

Swift 2.0 +

  let mainURL = "YOUR_URL_HERE"

    let url = NSURL(string: mainURL)
    let request = NSMutableURLRequest(URL: url!)
    let boundary = "78876565564454554547676"
    request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")


    request.HTTPMethod = "POST" // POST OR PUT What you want
    let session = NSURLSession(configuration:NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: nil, delegateQueue: nil)

    let imageData = UIImageJPEGRepresentation(UIImage(named: "Test.jpeg")!, 1)





    var body = NSMutableData()

    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

    // Append your parameters

    body.appendData("Content-Disposition: form-data; name=\"name\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("PREMKUMAR\r\n".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

    body.appendData("Content-Disposition: form-data; name=\"description\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("IOS_DEVELOPER\r\n".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)


    // Append your Image/File Data

    var imageNameval = "HELLO.jpg"

    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("Content-Disposition: form-data; name=\"profile_photo\"; filename=\"\(imageNameval)\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData("Content-Type: image/jpeg\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
    body.appendData(imageData!)
    body.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

    body.appendData("--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)

    request.HTTPBody = body




    let dataTask = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

        if error != nil {

            //handle error


        }
        else {




            let outputString : NSString = NSString(data:data!, encoding:NSUTF8StringEncoding)!
            print("Response:\(outputString)")


        }
    }
    dataTask.resume()

93

Eine weitere Option ist das Alamofire , die verkettbare Anforderungs- / Antwortmethoden bietet.

https://github.com/Alamofire/Alamofire

Eine Anfrage machen

import Alamofire

Alamofire.request(.GET, "http://httpbin.org/get")

Antwortbehandlung

Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
         .response { request, response, data, error in
              print(request)
              print(response)
              print(error)
          }

125
Ich denke, dass das Antworten mit einem Vorschlag für eine externe Bibliothek, während die Funktionalität vom Framework bereitgestellt wird, nicht der richtige Weg ist, dies zu tun.
Turkishweb

9
@turkishweb ist richtig. Cezars Antwort ist vollständiger und verwendet keine externen Bibliotheken. Das sollte die akzeptierte Antwort sein.
FredMaggiowski

11
Cezars Antwort ist veraltet (seit Swift 3) und die Benutzeroberfläche von Alamofire ist viel schöner als die von URLSessionund Consorts. Akzeptanz ist auch kein Maß für ein abstraktes Maß für Güte (geschweige denn für Ihr !;)), Sondern für das, was dem OP am meisten geholfen hat. (Für "reine" Lösungen gibt es SO-Dokumentation!) Wenn das diese Antwort war, perfekt - es werden keine ersten Prinzipien verwendet, aber das ist nicht immer die "richtige" Lösung, nicht wahr?
Raphael

9
Bitte bieten Sie keine Bibliotheken von Drittanbietern an, es sei denn, dies wird gemäß den SO-Richtlinien ausdrücklich verlangt
Alec O

1
Alamofire ist am besten
tania_S

36

Swift 4 und höher: Datenanforderung mithilfe der URLSession-API

   //create the url with NSURL
   let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")! //change the url

   //create the session object
   let session = URLSession.shared

   //now create the URLRequest object using the url object
   let request = URLRequest(url: url)

   //create dataTask using the session object to send data to the server
   let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in

       guard error == nil else {
           return
       }

       guard let data = data else {
           return
       }

      do {
         //create json object from data
         if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
            print(json)
         }
      } catch let error {
        print(error.localizedDescription)
      }
   })

   task.resume()

Swift 4 und höher, Decodable and Result enum

//APPError enum which shows all possible errors
enum APPError: Error {
    case networkError(Error)
    case dataNotFound
    case jsonParsingError(Error)
    case invalidStatusCode(Int)
}

//Result enum to show success or failure
enum Result<T> {
    case success(T)
    case failure(APPError)
}

//dataRequest which sends request to given URL and convert to Decodable Object
func dataRequest<T: Decodable>(with url: String, objectType: T.Type, completion: @escaping (Result<T>) -> Void) {

    //create the url with NSURL
    let dataURL = URL(string: url)! //change the url

    //create the session object
    let session = URLSession.shared

    //now create the URLRequest object using the url object
    let request = URLRequest(url: dataURL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 60)

    //create dataTask using the session object to send data to the server
    let task = session.dataTask(with: request, completionHandler: { data, response, error in

        guard error == nil else {
            completion(Result.failure(AppError.networkError(error!)))
            return
        }

        guard let data = data else {
            completion(Result.failure(APPError.dataNotFound))
            return
        }

        do {
            //create decodable object from data
            let decodedObject = try JSONDecoder().decode(objectType.self, from: data)
            completion(Result.success(decodedObject))
        } catch let error {
            completion(Result.failure(APPError.jsonParsingError(error as! DecodingError)))
        }
    })

    task.resume()
}

Beispiel:

// Wenn wir Aufgaben von der Platzhalter-API abrufen möchten, definieren wir die ToDo-Struktur, rufen dataRequest auf und übergeben die Zeichenfolgen-URL " https://jsonplaceholder.typicode.com/todos/1 ".

struct ToDo: Decodable {
    let id: Int
    let userId: Int
    let title: String
    let completed: Bool

}

dataRequest(with: "https://jsonplaceholder.typicode.com/todos/1", objectType: ToDo.self) { (result: Result) in
    switch result {
    case .success(let object):
        print(object)
    case .failure(let error):
        print(error)
    }
}

// dies gibt das Ergebnis aus:

ToDo(id: 1, userId: 1, title: "delectus aut autem", completed: false)

21

Grundlegende Swift 3+ -Lösung

guard let url = URL(string: "http://www.stackoverflow.com") else { return }

let task = URLSession.shared.dataTask(with: url) { data, response, error in

  guard let data = data, error == nil else { return }

  print(NSString(data: data, encoding: String.Encoding.utf8.rawValue))
}

task.resume()

3
Ihr Beispiel ist für Swift 3 , also sollten Sie URL(string: "http://www.stackoverflow.com")anstelle vonNSURL
FelixSFD

Casting von URL zu URL macht keinen SinnURLSession.shared.dataTask(with: url!)
Leo Dabus

Ich erhalte diesen Fehler:App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.

@YumYumYum Haben Sie die Sicherheit des App-Transports gemäß diesem Beitrag konfiguriert? Stackoverflow.com/questions/30731785/…
Ben Sullivan

Leo Dabus die variable URL ist vom Typ URL?
Tom Schulz

14

Ich verwende den Wrapper dieses Typen mit guten Ergebnissen. Https://github.com/daltoniam/swiftHTTP . Keine großen undichten Abstraktionen so weit

Beispiel

    do {
        let opt = try HTTP.GET("https://google.com")
        opt.start { response in
            if let err = response.error {
                print("error: \(err.localizedDescription)")
                return //also notify app of failure as needed
            }
            print("opt finished: \(response.description)")
            //print("data is: \(response.data)") access the response of the data with response.data
        }
    } catch let error {
        print("got an error creating the request: \(error)")
    }

3
Haben Sie eine Möglichkeit gefunden, auf den Abschluss der Anforderung zu warten, bevor Sie die Ansicht anzeigen? @ AlexanderN
Reshad

9

Einzelheiten

  • Xcode 9.2, Swift 4
  • Xcode 10.2.1 (10E1001), Swift 5

Info.plist

NSAppTransportSecurity

Zur Info-Liste hinzufügen:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Alamofire-Probe

Alamofire

import Alamofire

class AlamofireDataManager {
    fileprivate let queue: DispatchQueue
    init(queue: DispatchQueue) { self.queue = queue }

    private func createError(message: String, code: Int) -> Error {
        return NSError(domain: "dataManager", code: code, userInfo: ["message": message ])
    }

    private func make(session: URLSession = URLSession.shared, request: URLRequest, closure: ((Result<[String: Any]>) -> Void)?) {
        Alamofire.request(request).responseJSON { response in
            let complete: (Result<[String: Any]>) ->() = { result in DispatchQueue.main.async { closure?(result) } }
            switch response.result {
                case .success(let value): complete(.success(value as! [String: Any]))
                case .failure(let error): complete(.failure(error))
            }
        }
    }

    func searchRequest(term: String, closure: ((Result<[String: Any]>) -> Void)?) {
        guard let url = URL(string: "https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))") else { return }
        let request = URLRequest(url: url)
        make(request: request) { response in closure?(response) }
    }
}

Verwendung der Alamofire-Probe

private lazy var alamofireDataManager = AlamofireDataManager(queue: DispatchQueue(label: "DataManager.queue", qos: .utility))
//.........

alamofireDataManager.searchRequest(term: "jack johnson") { result in
      print(result.value ?? "no data")
      print(result.error ?? "no error")
}

URLSession-Beispiel

import Foundation

class DataManager {

    fileprivate let queue: DispatchQueue
        init(queue: DispatchQueue) { self.queue = queue }

    private func createError(message: String, code: Int) -> Error {
        return NSError(domain: "dataManager", code: code, userInfo: ["message": message ])
    }

    private func make(session: URLSession = URLSession.shared, request: URLRequest, closure: ((_ json: [String: Any]?, _ error: Error?)->Void)?) {
        let task = session.dataTask(with: request) { [weak self] data, response, error in
            self?.queue.async {
                let complete: (_ json: [String: Any]?, _ error: Error?) ->() = { json, error in DispatchQueue.main.async { closure?(json, error) } }

                guard let self = self, error == nil else { complete(nil, error); return }
                guard let data = data else { complete(nil, self.createError(message: "No data", code: 999)); return }

                do {
                    if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
                        complete(json, nil)
                    }
                } catch let error { complete(nil, error); return }
            }
        }

        task.resume()
    }

    func searchRequest(term: String, closure: ((_ json: [String: Any]?, _ error: Error?)->Void)?) {
        let url = URL(string: "https://itunes.apple.com/search?term=\(term.replacingOccurrences(of: " ", with: "+"))")
        let request = URLRequest(url: url!)
        make(request: request) { json, error in closure?(json, error) }
    }
}

Verwendung des URLSession-Beispiels

private lazy var dataManager = DataManager(queue: DispatchQueue(label: "DataManager.queue", qos: .utility))
// .......
dataManager.searchRequest(term: "jack johnson") { json, error  in
      print(error ?? "nil")
      print(json ?? "nil")
      print("Update views")
}

Ergebnisse

Geben Sie hier die Bildbeschreibung ein


searchRequest? Begriff? Woher kommen sie?
El Tomato

Dies ist ein vollständiges Beispiel der Anfrage. class func searchRequest(term: String, ...ist das Beispiel für das Herunterladen von Daten von itunes.apple.com. In diesem Beispiel wird gesucht, daher habe ich den searchRequestFunktionsnamen ausgewählt / erfunden . termist Teil " itunes.apple.com/search ?" Anfrage. Sie können beliebige Namen Ihrer Funktionen auswählen, die Ihr Logikmodell beschreiben.
Vasily Bodnarchuk

Schöne Lösung. Ich habe das geändert closure, um eine Aufzählung mit den Fällen successund zurückzugeben error.
Neoneye

7

Ich habe eine HTTP- Anforderung durchgeführt. Beide Methoden GET & POST mit JSON Parsing folgendermaßen :

on viewDidLoad () :

override func viewDidLoad() {
super.viewDidLoad()

    makeGetRequest()
    makePostRequest()

}

func makePostRequest(){

    let urlPath: String = "http://www.swiftdeveloperblog.com/http-post-example-script/"
    var url: NSURL = NSURL(string: urlPath)!
    var request: NSMutableURLRequest = NSMutableURLRequest(URL: url)

    request.HTTPMethod = "POST"
    var stringPost="firstName=James&lastName=Bond" // Key and Value

    let data = stringPost.dataUsingEncoding(NSUTF8StringEncoding)

    request.timeoutInterval = 60
    request.HTTPBody=data
    request.HTTPShouldHandleCookies=false

    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
        var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
        let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary

         if (jsonResult != nil) {
            // Success
           println(jsonResult)

           let message = jsonResult["Message"] as! NSString

           println(message)
         }else {
            // Failed
            println("Failed")
        }

    })

}

func makeGetRequest(){
    var url : String = "http://api.androidhive.info/contacts/"
    var request : NSMutableURLRequest = NSMutableURLRequest()
    request.URL = NSURL(string: url)
    request.HTTPMethod = "GET"
    request.timeoutInterval = 60

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, data: NSData!, error: NSError!) -> Void in
        var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil
        let jsonResult: NSDictionary! = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error: error) as? NSDictionary

        if (jsonResult != nil) {
            // Success
            println(jsonResult)

            let dataArray = jsonResult["contacts"] as! NSArray;

            for item in dataArray { // loop through data items

                let obj = item as! NSDictionary

                for (key, value) in obj {

                    println("Key: \(key) - Value: \(value)")

                    let phone = obj["phone"] as! NSDictionary;

                    let mobile = phone["mobile"] as! NSString
                    println(mobile)
                    let home = phone["home"] as! NSString
                    println(home)
                    let office = phone["office"] as! NSString
                    println(office)
                }
            }

        } else {
            // Failed
            println("Failed")
        }

    })
}

Erledigt


'SendAsynchronousRequest' kann nicht mit einer Argumentliste vom Typ 'aufgerufen werden (NSMutableURLRequest, Warteschlange: NSOperationQueue, CompletionHandler: (NSURLResponse!, NSData!, NSError!) -> Void)'
bMalum

4

Verwenden von URLSession + Swift 5

Wenn Sie nur die Antwort von cezar hinzufügen und eine Webanforderung mithilfe der URLSession-Klasse von Apple stellen möchten, gibt es mehrere Möglichkeiten, die Aufgabe auszuführen

  1. Einfache GET-Anfrage mit URL
  2. Einfache GET-Anfrage mit URL und Parametern
  3. Einfache GET-Anfrage mit URL mit Fehlerbehandlung
  4. Einfache POST-Anfrage mit URL, Parameter mit Fehlerbehandlung

1. Einfache GET-Anfrage mit URL

func simpleGetUrlRequest()
    {
        let url = URL(string: "https://httpbin.org/get")!

        let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
            guard let data = data else { return }
            print("The response is : ",String(data: data, encoding: .utf8)!)
            //print(NSString(data: data, encoding: String.Encoding.utf8.rawValue) as Any)
        }
        task.resume()
    }

Hinweis : Stellen Sie sicher, dass Sie den Schlüssel "NSAppTransportSecurity" in pList für http- Anforderungen hinzufügen müssen

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

2. Einfache GET-Anfrage mit URL und Parametern

func simpleGetUrlWithParamRequest()
    {
        let url = URL(string: "https://www.google.com/search?q=peace")!

        let task = URLSession.shared.dataTask(with: url) {(data, response, error) in

            if error != nil || data == nil {
                print("Client error!")
                return
            }
            guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
                print("Server error!")
                return
            }
            print("The Response is : ",response)
        }
        task.resume()
    }

3. Einfache GET-Anfrage mit URL mit Fehlerbehandlung

func simpleGetUrlRequestWithErrorHandling()
    {
        let session = URLSession.shared
        let url = URL(string: "https://httpbin.org/get")!

        let task = session.dataTask(with: url) { data, response, error in

            if error != nil || data == nil {
                print("Client error!")
                return
            }

            guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
                print("Server error!")
                return
            }

            guard let mime = response.mimeType, mime == "application/json" else {
                print("Wrong MIME type!")
                return
            }

            do {
                let json = try JSONSerialization.jsonObject(with: data!, options: [])
                print("The Response is : ",json)
            } catch {
                print("JSON error: \(error.localizedDescription)")
            }

        }
        task.resume()
    }

4. Einfache POST-Anfrage mit URL, Parameter mit Fehlerbehandlung.

func simplePostRequestWithParamsAndErrorHandling(){
        var session = URLSession.shared
        let configuration = URLSessionConfiguration.default
        configuration.timeoutIntervalForRequest = 30
        configuration.timeoutIntervalForResource = 30
        session = URLSession(configuration: configuration)

        let url = URL(string: "https://httpbin.org/post")!

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")

        let parameters = ["username": "foo", "password": "123456"]

        do {
            request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
        } catch let error {
            print(error.localizedDescription)
        }

        let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in

            if error != nil || data == nil {
                print("Client error!")
                return
            }

            guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
                print("Oops!! there is server error!")
                return
            }

            guard let mime = response.mimeType, mime == "application/json" else {
                print("response is not json")
                return
            }

            do {
                let json = try JSONSerialization.jsonObject(with: data!, options: [])
                print("The Response is : ",json)
            } catch {
                print("JSON error: \(error.localizedDescription)")
            }

        })

        task.resume()
    }

Ihre Vorschläge werden geschätzt !!


Warum verwenden Sie, var session = URLSession.sharedwenn Sie es nicht verwenden, sondern nur die Variable überschreiben? Wird es gebraucht?
vrwim

3

Ich rufe den json beim Anmelden an. Klicken Sie auf die Schaltfläche

@IBAction func loginClicked(sender : AnyObject) {

    var request = NSMutableURLRequest(URL: NSURL(string: kLoginURL)) // Here, kLogin contains the Login API.

    var session = NSURLSession.sharedSession()

    request.HTTPMethod = "POST"

    var err: NSError?
    request.HTTPBody = NSJSONSerialization.dataWithJSONObject(self.criteriaDic(), options: nil, error: &err) // This Line fills the web service with required parameters.
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
        var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
        var err1: NSError?
        var json2 = NSJSONSerialization.JSONObjectWithData(strData.dataUsingEncoding(NSUTF8StringEncoding), options: .MutableLeaves, error:&err1 ) as NSDictionary

        println("json2 :\(json2)")

        if(err) {
            println(err!.localizedDescription)
        }
        else {
            var success = json2["success"] as? Int
            println("Success: \(success)")
        }
    })

    task.resume()
}

Hier habe ich ein separates Wörterbuch für die Parameter erstellt.

var params = ["format":"json", "MobileType":"IOS","MIN":"f8d16d98ad12acdbbe1de647414495ec","UserName":emailTxtField.text,"PWD":passwordTxtField.text,"SigninVia":"SH"]as NSDictionary
    return params
}

// You can add your own sets of parameter here.

2

Sie können Just , eine python-requestsStil-HTTP-Bibliothek, verwenden.

Ein Beispiel für das Senden einer HTTP-Anfrage mit Just:

// synchronous GET request with URL query a=1
let r = Just.get("https://httpbin.org/get", params:["a":1])

// asynchronous POST request with form value and file uploads
Just.post(
    "http://justiceleauge.org/member/register",
    data: ["username": "barryallen", "password":"ReverseF1ashSucks"],
    files: ["profile_photo": .URL(fileURLWithPath:"flash.jpeg", nil)]
) { (r)
    if (r.ok) { /* success! */ }
}

In beiden Fällen kann auf das Ergebnis einer Anforderung rauf ähnliche Weise zugegriffen werden python-request:

r.ok            // is the response successful?
r.statusCode    // status code of response
r.content       // response body as NSData?
r.text          // response body as text?
r.json          // response body parsed by NSJSONSerielization

Weitere Beispiele finden Sie auf diesem Spielplatz

Die Verwendung dieser Bibliothek im synchronen Modus auf einem Spielplatz kommt CURL in Swift am nächsten.


Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert.
dimo414

Es scheint, dass diese Bibliothek veraltet ist. Keine Swift 4-Unterstützung und niemand reagiert auf offene Probleme.
Heinrisch

2

In Swift 4.1 und Xcode 9.4.1.

Beispiel für einen JSON POST- Ansatz. Um die Internetverbindung zu überprüfen, fügen Sie Reachability.h & .m-Dateien von https://developer.apple.com/library/archive/samplecode/Reachability/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007324-Intro-DontLinkElementID_2 hinzu

func yourFunctionName {
    //Check internet connection
    let networkReachability = Reachability.forInternetConnection()
    let networkStatus:Int = (networkReachability?.currentReachabilityStatus())!.rawValue
    print(networkStatus)
    if networkStatus == NotReachable.rawValue {
        let msg = SharedClass.sharedInstance.noNetMsg//Message
        //Call alert from shared class
        SharedClass.sharedInstance.alert(view: self, title: "", message: msg)
    } else {
        //Call spinner from shared class
        SharedClass.sharedInstance.activityIndicator(view: self.view)//Play spinner

        let parameters = "Your parameters here"
        var request = URLRequest(url: URL(string: url)!)

        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"

        print("URL : \(request)")

        request.httpBody = parameters.data(using: .utf8)

        let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { // check for fundamental networking error
            //Stop spinner
            SharedClass.sharedInstance.stopActivityIndicator() //Stop spinner
            //Print error in alert
            SharedClass.sharedInstance.alert(view: self, title: "", message: "\(String(describing: error!.localizedDescription))")
            return
            }

            SharedClass.sharedInstance.stopActivityIndicator() //Stop spinner

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(String(describing: response))")
            }

            do {
                let response = try JSONSerialization.jsonObject(with: data, options: []) as? [String: AnyObject]
                print(response!)
                //Your code here                    
            } catch let error as NSError {
                print(error)
            }
        }

        task.resume()

    }

}

Wenn Sie Interesse haben, diese Funktion in SharedClass zu verwenden

//My shared class
import UIKit
class SharedClass: NSObject {

static let sharedInstance = SharedClass()

func postRequestFunction(apiName: String , parameters: String, onCompletion: @escaping (_ success: Bool, _ error: Error?, _ result: [String: Any]?)->()) {

    var URL =  "your URL here/index.php/***?"

    URL = URL.replacingOccurrences(of: "***", with: apiName)

    var request = URLRequest(url: URL(string: URL)!)
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.httpMethod = "POST"
    print("shared URL : \(request)")
    request.httpBody = parameters.data(using: .utf8)

    var returnRes:[String:Any] = [:]
    let task = URLSession.shared.dataTask(with: request) { data, response, error in

        if let error = error {
            onCompletion(false, error, nil)
        } else {
            guard let data = data else {
                onCompletion(false, error, nil)
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode == 200 {
                do {
                   returnRes = try JSONSerialization.jsonObject(with: data, options: []) as! [String : Any]
                    onCompletion(true, nil, returnRes)

                } catch let error as NSError {
                   onCompletion(false, error, nil)
                }
            } else {
                onCompletion(false, error, nil)
            }
        }
    }
    task.resume()
}


private override init() {

}

Und schließlich rufen Sie diese Funktion so auf ...

SharedClass.sharedInstance.postRequestFunction(apiName: "Your API name", parameters: parameters) { (success, error, result) in
    print(result!)
    if success {
        //Your code here
    } else {
        print(error?.localizedDescription ?? "")
    }
}

1

Ein einfacher Swift 2.0-Ansatz zum Erstellen einer HTTP-GET-Anforderung

Die HTTP-Anforderung ist asynchron, sodass Sie eine Möglichkeit benötigen, den zurückgegebenen Wert aus der HTTP-Anforderung abzurufen. Dieser Ansatz verwendet Notifizierer und ist auf zwei Klassen verteilt.

Das Beispiel besteht darin, den Benutzernamen und das Kennwort auf der Website http://www.example.com/handler.php?do=CheckUserJson&json= auf ein Kennungstoken zu überprüfen. Die Datei heißt handler.php und hat eine switch-Anweisung auf der do-Parameter, um einen RESTful-Ansatz zu erhalten.

In viewDidLoad richten wir den NotifierObserver ein, richten den json ein und rufen die Funktion getHTTPRequest auf. Es wird mit dem zurückgegebenen Parameter aus der http-Anforderung zur Funktion verifyUsernameAndPassword zurückgekehrt.

override func viewDidLoad() {
    super.viewDidLoad()
    // setup the Notification observer to catch the result of check username and password
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "checkedUsernameAndPassword:", name: CHECK_USERNAME_AND_PASSWORD, object: nil)        
    let username = GlobalVariables.USER_NAME
    let password = GlobalVariables.PASSWORD
    // check username and password
    if let jsonString = Utility.checkUsernameAndPasswordJson(username, password:password){
        print("json string returned = \(jsonString)")
        let url = CHECKUSERJSON+jsonString
        // CHECKUSERJSON = http://www.example.com/handler.php?do=CheckUserJson&json=
        // jsonString = {\"username\":\"demo\",\"password\":\"demo\"}"
        // the php script handles a json request and returns a string identifier           
        Utility.getHTTPRequest(url,notifierId: CHECK_USERNAME_AND_PASSWORD)
        // the returned identifier is sent to the checkedUsernaeAndPassword function when it becomes availabel.
    }
}

In Utility.swift gibt es zwei statische Funktionen, um zuerst den json zu codieren und dann den HTTP-Aufruf auszuführen.

    static func checkUsernameAndPasswordJson(username: String, password: String) -> String?{
    let para:NSMutableDictionary = NSMutableDictionary()
        para.setValue("demo", forKey: "username")
        para.setValue("demo", forKey: "password")
    let jsonData: NSData
    do{
        jsonData = try NSJSONSerialization.dataWithJSONObject(para, options: NSJSONWritingOptions())
        let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding) as! String
        return jsonString
    } catch _ {
        print ("UH OOO")
        return nil
    }
}

und die HTTP-Anfrage

    static func getHTTPRequest (url:String , notifierId: String) -> Void{
    let urlString = url
    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: config, delegate: nil, delegateQueue: nil)
    let safeURL = urlString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
    if let url = NSURL(string: safeURL){
        let request  = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "GET"
        request.timeoutInterval = 60
        let taskData = session.dataTaskWithRequest(request, completionHandler: {
            (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
            if (data != nil) {
                let result = NSString(data: data! , encoding: NSUTF8StringEncoding)
                sendNotification (notifierId, message: String(result), num: 0)
            }else{
                  sendNotification (notifierId, message: String(UTF8String: nil), num: -1)                    }
        })
    taskData.resume()
    }else{
        print("bad urlString = \(urlString)")
    }
}

Die sendNotification-Funktion schließt den Kreis. Beachten Sie, dass im Observer am Ende der Auswahlzeichenfolge ein ":" steht. Dadurch kann die Benachrichtigung eine Nutzlast in userInfo übertragen. Ich gebe diesem einen String und einen Int.

    static func sendNotification (key: String, message:String?, num: Int?){
    NSNotificationCenter.defaultCenter().postNotificationName(
        key,
        object: nil,
        userInfo:   (["message": message!,
                      "num": "\(num!)"])
    )
}

Beachten Sie, dass die Verwendung von HTTP altmodisch ist. Bevorzugen Sie HTTPS. Siehe Wie lade ich eine HTTP-URL mit aktivierter App Transport Security in iOS 9?


0
 var post:NSString = "api=myposts&userid=\(uid)&page_no=0&limit_no=10"

    NSLog("PostData: %@",post);

    var url1:NSURL = NSURL(string: url)!

    var postData:NSData = post.dataUsingEncoding(NSASCIIStringEncoding)!

    var postLength:NSString = String( postData.length )

    var request:NSMutableURLRequest = NSMutableURLRequest(URL: url1)
    request.HTTPMethod = "POST"
    request.HTTPBody = postData
    request.setValue(postLength, forHTTPHeaderField: "Content-Length")
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json", forHTTPHeaderField: "Accept")

    var reponseError: NSError?
    var response: NSURLResponse?

    var urlData: NSData? = NSURLConnection.sendSynchronousRequest(request, returningResponse:&response, error:&reponseError)

    if ( urlData != nil ) {
        let res = response as NSHTTPURLResponse!;

        NSLog("Response code: %ld", res.statusCode);

        if (res.statusCode >= 200 && res.statusCode < 300)
        {
            var responseData:NSString  = NSString(data:urlData!, encoding:NSUTF8StringEncoding)!

            NSLog("Response ==> %@", responseData);

            var error: NSError?

            let jsonData:NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers , error: &error) as NSDictionary

            let success:NSInteger = jsonData.valueForKey("error") as NSInteger

            //[jsonData[@"success"] integerValue];

            NSLog("Success: %ld", success);

            if(success == 0)
            {
                NSLog("Login SUCCESS");

                self.dataArr = jsonData.valueForKey("data") as NSMutableArray
                self.table.reloadData()

            } else {

                NSLog("Login failed1");
                ZAActivityBar.showErrorWithStatus("error", forAction: "Action2")
            }

        } else {

            NSLog("Login failed2");
            ZAActivityBar.showErrorWithStatus("error", forAction: "Action2")

        }
    } else {

        NSLog("Login failed3");
        ZAActivityBar.showErrorWithStatus("error", forAction: "Action2")
}

es wird dir sicher helfen


0

// Hier ist ein Beispiel, das für mich funktioniert hat

// Schnelle Funktion, die eine Anfrage an einen Server mit Schlüsselwerten sendet

func insertRecords()
{



    let usrID = txtID.text
    let checkin = lblInOut.text
    let comment = txtComment.text



    // The address of the web service
    let urlString = "http://your_url/checkInOut_post.php"

    // These are the keys that your are sending as part of the post request
    let keyValues = "id=\(usrID)&inout=\(checkin)&comment=\(comment)"




    // 1 - Create the session by getting the configuration and then
    //     creating the session

    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: config, delegate: nil, delegateQueue: nil)


    // 2 - Create the URL Object

    if let url = NSURL(string: urlString){


        // 3 - Create the Request Object

        var request  = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "POST"

        // set the key values
        request.HTTPBody = keyValues.dataUsingEncoding(NSUTF8StringEncoding);


        // 4 - execute the request

        let taskData = session.dataTaskWithRequest(request, completionHandler: {

            (data:NSData!, response:NSURLResponse!, error:NSError!) -> Void in

            println("\(data)")

            // 5 - Do something with the Data back

            if (data != nil) {

                // we got some data back
                println("\(data)")

                let result = NSString(data: data , encoding: NSUTF8StringEncoding)
                println("\(result)")

                if result == "OK" {

                    let a = UIAlertView(title: "OK", message: "Attendece has been recorded", delegate: nil, cancelButtonTitle: "OK")

                    println("\(result)")

                    dispatch_async(dispatch_get_main_queue()) {


                    a.show()


                    }


                } else {
                  // display error and do something else

                }


            } else

            {   // we got an error
                println("Error getting stores :\(error.localizedDescription)")

            }


        })

        taskData.resume()



    }


}

PHP-Code zum Abrufen der Schlüsselwerte

$ empID = $ _POST ['id'];

$ inOut = $ _POST ['inout'];

$ comment = $ _POST ['comment'];


0

Hier ist ein sehr einfaches Swift 4- Beispiel auf einem Spielplatz:

import UIKit
// run asynchronously in a playground
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

// create a url
let url = URL(string: "http://www.stackoverflow.com")

// create a data task
let task = URLSession.shared.dataTask(with: url!) { (data, response, error) in
    if error != nil {
        print("there's a problem")
    }
    print(String(data: data!, encoding: String.Encoding.utf8) ?? "")
}

//running the task w/ resume
task.resume()

0

Damit XCUITest den Testabschluss vor Abschluss der asynchronen Anforderung beendet, verwenden Sie Folgendes (möglicherweise verringern Sie das Zeitlimit von 100):

func test_api() {
    let url = URL(string: "https://jsonplaceholder.typicode.com/posts/42")!
    let exp = expectation(description: "Waiting for data")
    let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
        guard let data = data else { return }
        print(String(data: data, encoding: .utf8)!)
        exp.fulfill()
    }
    task.resume()
    XCTWaiter.wait(for: [exp], timeout: 100)
}

0

KISS Antwort:

URLSession.shared.dataTask(with: URL(string: "https://google.com")!) {(data, response, error) in
    print(String(data: data!, encoding: .utf8))
}.resume()

-2

Ein Beispiel für eine Beispielanforderung "GET" ist unten angegeben.

let urlString = "YOUR_GET_URL"
let yourURL = URL(string: urlstring)
let dataTask = URLSession.shared.dataTask(with: yourURL) { (data, response, error) in
do {
    let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
    print("json --- \(json)")
    }catch let err {
    print("err---\(err.localizedDescription)")
    }
   }
dataTask.resume()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.