学习swift继续延续之前的思路,对照着OC学,从UI起手,学习到对应的自适应布局。
今天再次学习了swift的原生网络请求和对应的第三方库-Alamofire。
Swift Package Manager
。Swift Package Manager
的url。 // 普通的网络请求
func makeLogon() {
// 构建URL
let url:URL = URL(string: "https://news-at.zhihu.com/api/4/news/latest")!
// 发送HTTP请求的的session对象
let session = URLSession.shared
// 构建请求request
var request = URLRequest(url: url)
request.httpMethod = "GET"
// 发一个get请求
let task = session.dataTask(with: request as URLRequest) {(
data, response, error) in
guard let data = data, let _:URLResponse = response, error == nil else {
print("Request Erroor")
return
}
let dataString = String(data: data, encoding: String.Encoding.utf8)
let dict = self.getDictionaryFromJSONString(jsonString: dataString!)
print(dict)
}
task.resume()
}
这段代码是使用 URLSession 发起 GET 请求,并将返回的数据转换为字典类型。
首先,通过 session.dataTask(with:completionHandler:)
方法创建一个任务对象,并在闭包中处理请求的结果。
在闭包中,首先使用可选绑定 guard let
检查请求的返回数据 data
是否存在,以及响应 response
是否存在且是 URLResponse
类型,并检查是否有错误 error
。如果其中任何一个条件不满足,就会打印错误信息并返回。
如果没有错误,我们将返回的数据 data
使用 String(data:encoding:)
方法转换为字符串类型,并存储在 dataString
变量中。
接下来,调用 getDictionaryFromJSONString(jsonString:)
方法将字符串类型的数据 dataString
转换为字典类型。
最后,打印转换后的字典 dict
。
getDictionaryFromJSONString(jsonString:)
是一个自定义的方法,用于将 JSON 字符串转换为字典类型。
func getDictionaryFromJSONString(jsonString: String) -> NSDictionary {
// 将传入的 JSON 字符串 jsonString 使用 data(using:) 方法转换为 Data 类型
let jsonData:Data = jsonString.data(using: .utf8)!
// 通过 JSONSerialization.jsonObject(with:options:) 方法将 jsonData 进行 JSON 解析,并将解析结果存储在 dict 变量中。这里使用的选项是 .mutableContainers,表示可以修改容器对象
let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
// 使用条件语句判断 dict 是否为 nil。如果不为 nil,表示 JSON 解析成功,将 dict 强制转换为 NSDictionary 类型,并返回。
// 如果 dict 为 nil,表示 JSON 解析失败,返回一个空的 NSDictionary 对象。
if dict != nil {
return dict as! NSDictionary
}
return NSDictionary()
}
这里还是以get请求为例,请求一下知乎日报的接口
static let shareSingenal = Mananger()
构建函数,发送请求
这里用到了swift的闭包来写succeed或者failure的回调。
用到了if let 语法:很安全
func getWithPath(path: String,paras: Dictionary<String,Any>?,success: @escaping ((_ result: Any) -> ()),failure: @escaping ((_ error: Error) -> ())) {
// var i = 0
let address = path
// 首先,定义了变量 i 和 address,用于拼接完整的 URL 地址。
// if let paras = paras {
// for (key,value) in paras {
// if i == 0 {
// address += "?\(key)=\(value)"
// }else {
// address += "&\(key)=\(value)"
// }
// i += 1
// }
// }
// 完成参数拼接后,通过 URL(string:) 方法将拼接后的 address 转换为 URL 对象。
let url = URL(string: address.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!)
// 使用 URLSession.shared 创建一个共享的会话对象,并通过 dataTask(with:completionHandler:) 方法发起网络请求。
let session = URLSession.shared
let dataTask = session.dataTask(with: url!) { (data, respond, error) in
if let data = data {
// 在网络请求的回调闭包中,首先判断返回的数据 data 是否存在。如果存在,则通过 JSONSerialization.jsonObject(with:options:) 方法将数据进行 JSON 解析,并将解析结果传递给成功回调闭包 success。
if let result = try? JSONSerialization.jsonObject(with: data, options: .allowFragments){
success(result)
}
}else {
// 如果数据不存在,即请求失败,将错误信息 error 传递给失败回调闭包 failure。
failure(error!)
}
}
// 通过调用 dataTask.resume() 方法开始执行网络请求。
dataTask.resume()
}
}
Alamofire
是使用Swift
语言开发的网络库,它和AFNetworking
很像Alamofire
使用链式编程实现的。具有简洁的语法,良好的性能和优秀的可读性等特点。Alamofire
,本质上是基于NSURLSession
进行封装的,其核心是URLSession
和URLSessionTask
子类。其早期版本使用Alamofire.request
(),5.0之后使用AF.request
()。本质上第三方库是为了减轻我们的压力,缩减了请求过程的代码。
最基础的就是发送一个GET请求
func sendReqWithAlamofire() -> Void {
let url: URL = URL(string: "https://news-at.zhihu.com/api/4/news/latest")!
AF.request(url).response { response in
switch response.result {
case let .success(data):
print("data:\(String(describing: data))")
case let .failure(error):
print(error)
}
}
}
能看出来,已经帮我们封装好了succeed和failure的回调。
Alamofire
中,response
的 data
属性是一个可选类型 Data?
。因此,打印结果中显示的 Optional
表示该值是可选的。而 3643 bytes 表示返回的数据的字节数,这个值会根据实际返回的数据大小而变化。针对AF的request
请求接口,Alamofire
封装了三个同名接口,三个接口是针对不同的参数进行设置的。
open func request(_ convertible: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil,
requestModifier: RequestModifier? = nil)
open func request<Parameters: Encodable>(_ convertible: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil,
requestModifier: RequestModifier? = nil)
open func request(_ convertible: URLRequestConvertible, interceptor: RequestInterceptor? = nil)
参数一: convertible
(可变化)一个可变化的参数。其实就是请求的url地址。
参数二:method
请求方式。就是我们常说的GET,POST。
参数三:parameters
请求参数。业务数据的参数部分,如登录模块的userName
,Password
等之类的业务数据。
参数四:encoding
编码方式。Alamofire
支持两种编码方式:
JSONParameterEncoder
和- URLEncodedFormParameterEncoder
若encoding设置为JSONEncoding, 即为JSON格式。参数五: headers
请求头参数。http
请求中请求头的参数设置,支持Json
格式,例如设置token
,cookie
等参数。这个还是根据接口不同来写不同的需求。
参数六: interceptor
请求拦截器,主要用来在请求流程中拦截请求,并对请求进行一些必要的处理,(没用过)
参数七:requestModifier
请求修改器。在请求流程中修改数据,例如针对特定请求,不使用默认超时时间,而自定义超时时间
Alamofire支持4种返回响应处理方式:Data、String、 JSON、自定义类型。
let url: URL = URL(string: "https://news-at.zhihu.com/api/4/news/latest")!
//Data示例
AF.request(url).responseData { response in
switch response.result {
case let .success(data):
print("data:\(String(describing: data))")
case let .failure(error):
print(error)
}
}
//String示例
AF.request(url).responseString { response in
switch response.result {
case let .success(data):
print("data:\(String(describing: data))")
case let .failure(error):
print(error)
}
}
//JSON示例
AF.request(url).responseJSON { response in
switch response.result {
case let .success(data):
print("data:\(String(describing: data))")
case let .failure(error):
print(error)
}
}
//自定义格式示例
struct PersonResponse: Decodable { let name: String, let nickName : String, let age : Int }
AF.request(url).responseDecodable(of: PersonResponse.self) { response in
switch response.result {
case let .success(data):
print("data:\(String(describing: data))")
case let .failure(error):
print(error)
}
}
语言的安全性很强,还是先使用了if let结构,也是在succeed的回调里面使用的
func sendReqWithAlamofire() -> Void {
let url: URL = URL(string: "https://news-at.zhihu.com/api/4/news/latest")!
AF.request(url).response { response in
switch response.result {
// 涉及到了语言的安全性
case let .success(data):
print("Successd get ReqWithAla")
print(data as Any)
// 转字符串
if let responseData = data {
let dataString = String(data: responseData, encoding: .utf8)
print("data: \(String(describing: dataString))")
}
// print("data:\(String(describing: data))")
// 转字典
if let responseData = data {
do {
// 首先使用可选绑定 if let 检查 data 是否存在。如果 data 存在,我们尝试使用 JSONSerialization.jsonObject(with:options:) 方法将数据解析为字典类型。
if let jsonToDict = try JSONSerialization.jsonObject(with: responseData, options: []) as? [String: Any] {
// 使用转换后的字典进行进一步操作
print("data: \(jsonToDict)")
}
} catch {
// 解析失败,会抛出异常,我们可以使用 catch 块来捕获异常并进行相应的错误处理。
print("Failed to parse JSON: \(error)")
}
}
case let .failure(error):
print(error)
}
}
}
}
和AFN库一样使用起来简单快捷,swift的语言特性安全在很多处都会体现,接下来会学习swift的原声json Model解析库。