我在iBooks上读了苹果的编程语言Swift,但不知道如何在Swift中发出HTTP请求(类似cURL)。我需要导入Obj-C类还是只需要导入默认库?或者不能基于原生Swift代码进行HTTP请求?
当前回答
在Swift 4.1和Xcode 9.4.1中。
JSON POST方法示例。要检查互联网连接,从https://developer.apple.com/library/archive/samplecode/Reachability/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007324-Intro-DontLinkElementID_2添加Reachability.h & .m文件
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()
}
}
如果你有兴趣在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() {
}
最后像这样调用这个函数....
SharedClass.sharedInstance.postRequestFunction(apiName: "Your API name", parameters: parameters) { (success, error, result) in
print(result!)
if success {
//Your code here
} else {
print(error?.localizedDescription ?? "")
}
}
其他回答
你可以使用URL URLRequest URLSession或者NSURLConnection就像你在Objective-C中通常做的那样。注意,对于iOS 7.0及更高版本,URLSession是首选。
使用URLSession
初始化URL对象和URLSession中的URLSessionDataTask。然后使用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()
使用NSURLConnection
首先,初始化URL和URLRequest:
let url = URL(string: "http://www.stackoverflow.com")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
然后,你可以异步加载请求:
NSURLConnection.sendAsynchronousRequest(request, queue: OperationQueue.main) {(response, data, error) in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}
或者你可以初始化一个NSURLConnection:
let connection = NSURLConnection(request: request, delegate:nil, startImmediately: true)
只是要确保将委托设置为nil以外的东西,并使用委托方法处理接收到的响应和数据。
要了解更多细节,请查看NSURLConnectionDataDelegate协议的文档
在Xcode操场上测试
如果你想在Xcode游乐场上尝试这段代码,添加import PlaygroundSupport到你的游乐场,以及下面的调用:
PlaygroundPage.current.needsIndefiniteExecution = true
这将允许你在操场上使用异步代码。
细节
Xcode 9.2, Swift 4 Xcode 10.2.1 (10E1001)
Info.plist
NSApp传输安全
添加到info plist:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Alamofire样本
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) }
}
}
Alamofire样品的使用
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样本
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) }
}
}
URLSession示例的使用
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")
}
结果
为了让XCUITest在异步请求完成之前停止测试完成,使用这个(可能会减少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)
}
我已经完成了HTTP请求两种方法GET和POST与JSON解析的方式:
在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")
}
})
}
Done
在Swift 4.1和Xcode 9.4.1中。
JSON POST方法示例。要检查互联网连接,从https://developer.apple.com/library/archive/samplecode/Reachability/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007324-Intro-DontLinkElementID_2添加Reachability.h & .m文件
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()
}
}
如果你有兴趣在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() {
}
最后像这样调用这个函数....
SharedClass.sharedInstance.postRequestFunction(apiName: "Your API name", parameters: parameters) { (success, error, result) in
print(result!)
if success {
//Your code here
} else {
print(error?.localizedDescription ?? "")
}
}
推荐文章
- NSLayoutConstraints是可动画的吗?
- iOS -构建失败,CocoaPods无法找到头文件
- Xcode 4挂在“附加到(应用程序名称)”
- CFNetwork SSLHandshake iOS 9失败
- swift语言中的结构与类
- 我如何在Swift连接字符串?
- 请求失败:不可接受的内容类型:文本/html使用AFNetworking 2.0
- 缺少推荐的图标文件-该包不包含iPhone / iPod Touch的应用程序图标,像素为“120x120”,png格式
- 以编程方式创建segue
- 在Objective-C中@synchronized如何锁定/解锁?
- 什么是HTTP“主机”报头?
- 我应该如何从字符串中删除所有的前导空格?- - - - - -斯威夫特
- Xcode构建失败“架构x86_64未定义的符号”
- 如何使用Xcode创建。ipa文件?
- 动态改变UILabel的字体大小