How do I make an HTTP request in Swift?

前端 未结 20 1089
不知归路
不知归路 2020-11-22 05:10

I read The Programming Language Swift by Apple in iBooks, but cannot figure out how to make an HTTP request (something like cURL) in Swift. Do I need to import Obj-C classes

相关标签:
20条回答
  • 2020-11-22 05:50

    Details

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

    Info.plist

    NSAppTransportSecurity

    Add to the info plist:

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

    Alamofire Sample

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

    Usage of Alamofire sample

    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 Sample

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

    Usage of URLSession sample

    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")
    }
    

    Results

    0 讨论(0)
  • 2020-11-22 05:52

    In Swift 4.1 and Xcode 9.4.1.

    JSON POST approach example. To check internet connection add Reachability.h & .m files from https://developer.apple.com/library/archive/samplecode/Reachability/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007324-Intro-DontLinkElementID_2

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

    If you have interest to use this function in SharedClass

    //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() {
    
    }
    

    And finally call this function like this....

    SharedClass.sharedInstance.postRequestFunction(apiName: "Your API name", parameters: parameters) { (success, error, result) in
        print(result!)
        if success {
            //Your code here
        } else {
            print(error?.localizedDescription ?? "")
        }
    }
    
    0 讨论(0)
  • 2020-11-22 05:53

    Another option is the Alamofire lib that offers Chainable Request / Response methods.

    https://github.com/Alamofire/Alamofire

    Making a Request

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

    Response Handling

    Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
             .response { request, response, data, error in
                  print(request)
                  print(response)
                  print(error)
              }
    
    0 讨论(0)
  • 2020-11-22 05:54

    Here's a very simple Swift 4 example in a playground:

    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 讨论(0)
  • 2020-11-22 05:55

    KISS answer:

    URLSession.shared.dataTask(with: URL(string: "https://google.com")!) {(data, response, error) in
        print(String(data: data!, encoding: .utf8))
    }.resume()
    
    0 讨论(0)
  • 2020-11-22 05:59

    You can use URL, URLRequest and URLSession or NSURLConnection as you'd normally do in Objective-C. Note that for iOS 7.0 and later, URLSession is preferred.

    Using URLSession

    Initialize a URL object and a URLSessionDataTask from URLSession. Then run the task with 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()
    

    Using NSURLConnection

    First, initialize a URL and a URLRequest:

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

    Then, you can load the request asynchronously with:

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

    Or you can initialize an NSURLConnection:

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

    Just make sure to set your delegate to something other than nil and use the delegate methods to work with the response and data received.

    For more detail, check the documentation for the NSURLConnectionDataDelegate protocol

    Testing on an Xcode playground

    If you want to try this code on a Xcode playground, add import PlaygroundSupport to your playground, as well as the following call:

    PlaygroundPage.current.needsIndefiniteExecution = true
    

    This will allow you to use asynchronous code in playgrounds.

    0 讨论(0)
提交回复
热议问题