这是我参与更文挑战的第17天,活动详情查看: 更文挑战
Alamofire三种数据结果流
- response
- responseJSON
- responseDecodable
response
AF.request("http://app.u17.com/v3/appV3_3/ios/phone/comic/boutiqueListNew").response { (response:AFDataResponse) in
返回的数据流,如果要直接使用,需要通过JSONSerialization 进行转化成JSON格式;然后再通过手动解析除数据
1.首先将json数据转化为dict
2.在根据json的数据中获得String类型的origin
3.如果json数据中有dict,我们在进行一次转化为dict,类型为String和String是因为键值对是这个类型。
4.根据dict里面我们需要的数据进行取出。
5.我们就可以当做常量来使用这些数据了
demo
AF.request(boutiqueListNewURL).response { (response:AFDataResponse) in
switch response.result {
case .success(let JSON):
do {
let JSONObject = try? JSONSerialization.jsonObject(with: JSON ?? Data(), options: .allowFragments)
if let JSON = JSONObject as? [String:Any] {
debugPrint(JSON.debugDescription)
let data = JSON["data"] as! [String:Any]
let returnData = data["returnData"] as! [String:Any]
let comicLists = returnData["comicLists"] as! NSArray
let comics = comicLists[0] as! [String:Any]
let itemTitle = comics["itemTitle"] as! String
debugPrint("itemTitle: \(itemTitle)")
}
} catch _ {
// print(error)
}
case .failure(let error):
debugPrint(error)
}
}
复制代码
responseJSON
AF.request(boutiqueListNewURL, method: .get).responseJSON {response in
故名思义直接返回的JSON数据格式,同上
AF.request(boutiqueListNewURL, method: .get).responseJSON {response in
switch response.result {
case .success(let value as [String: Any]):
debugPrint("success: \(String(describing: value["code"]))")
let data = value["data"] as! [String:Any]
let returnData = data["returnData"] as! [String:Any]
let comicLists = returnData["comicLists"] as! NSArray
// let comics = comicLists[0] as! [String:Any]
// let itemTitle = comics["itemTitle"] as! String
//print("itemTitle: \(itemTitle)")
self.comicList = comicLists.map { list in
let item = ComicList()
if let list = list as? [String:Any] {
let comicsList = list["comics"] as? NSArray
if comicsList?.count ?? 0 > 0 {
let comics = comicsList?[0] as! [String:Any]
item.itemTitle = comics["short_description"] as? String
}
}
return item
}
self.tableView.reloadData()
case .failure(let error):
debugPrint("Failure: \(error)")
default: fatalError("Fatal error.")
}
}
复制代码
responseDecodable
AF.request(boutiqueListNewURL).responseDecodable
支持Decodable 协议,U17Root 遵守的Decodable协议,对应的就能把原始数据转化成Model对象
这简直太幸福了,不需要关心数据安全类型还是可选类型,不需要先进行数组,字典类型确认后再解析,现在一步到位,一行代码就能搞定。
你要做的就是保证解析的应的JSON对象是遵守Codable协议的,这样也不用关系JSON是否是嵌套的还是普通格式;
AF.request(boutiqueListNewURL).responseDecodable(of: U17Root.self) { response in
debugPrint("Response: \(response)")
debugPrint("comicListsL Response: \(response.value?.data?.returnData?.comicLists?[0].itemTitle ?? "1000")")
self.comicList = response.value?.data?.returnData?.comicLists
self.tableView.reloadData()
}
复制代码
U17Root 定义
U17Root 对象其实还是挺复杂的,手动解析下来是真的太累了,对象嵌套数组,数组嵌套对象再嵌套数组对象
import Foundation
class U17Root: Codable {
// 如果你希望自己的模型仅仅只是接受网络请求获取的数据,不做任何改变,那么建议使用let 而不是使用var
let code: Int?
let data: U17Data?
}
class U17Data: Codable {
var message: String?
var returnData: ReturnData?
var stateCode: Int?
}
class ReturnData: Codable {
var comicLists: [ComicList]?
var editTime: String?
var galleryItems: [GalleryItem]?
/// 这个是我自定义的模型属性
var isMoreThanOneComic: Bool = false
enum CodingKeys: String, CodingKey {
case comicLists = "comicLists"
case editTime = "editTime"
case galleryItems = "galleryItems"
}
init() { }
/*
如果模型里面有自定义的属性
也就是根据从服务器获取JSON推导出来的其他属性赋值的时候
需要写出Decodable协议实现的完整方法,注意 将init() {}也声明出来,否者你根本没有一个正常的初始化方法可以用
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
comicLists = try values.decodeIfPresent([ComicList].self, forKey: .comicLists)
editTime = try values.decodeIfPresent(String.self, forKey: .editTime)
galleryItems = try values.decodeIfPresent([GalleryItem].self, forKey: .galleryItems)
// 自定义模型属性的赋值
if let comicLists = comicLists, comicLists.count > 1 {
isMoreThanOneComic = true
}else {
isMoreThanOneComic = false
}
}
}
class GalleryItem: Codable {
var content: String?
var cover: String?
var ext: [Ext]?
var id: Int?
var linkType: Int?
var title: String?
}
class Ext: Codable {
var key: String?
var val: String?
}
class ComicList: Codable {
var argName: String?
var argType: Int?
var argValue: Int?
var canedit: Int?
var comicType: Int?
var comics: [Comic]?
var descriptionField: String?
var itemTitle: String?
var newTitleIconUrl: String?
var sortId: String?
var titleIconUrl: String?
}
class Comic: Codable {
var authorName: String?
var comicId: Int?
var cornerInfo: String?
var cover: String?
var descriptionField: String?
var isVip: Int?
var name: String?
var shortDescription: String?
var subTitle: String?
var tags: [String]?
}
复制代码
注意⚠️
一定要保证解析JSON对象类型和实体类型是对应的;假出json是一个map结构,而你定义的是一个Array类型变量接收
这里是会报JSON解析异常的!
responseDecodable实现分析
对于responseDecodable 实现方式简单的记录
/// The tpe to which all data response serializers must conform in order to serialize a response.
public protocol DataResponseSerializerProtocol {
/// The type of serialized object to be created.
associatedtype SerializedObject
/// Serialize the response `Data` into the provided type..
///
/// - Parameters:
/// - request: `URLRequest` which was used to perform the request, if any.
/// - response: `HTTPURLResponse` received from the server, if any.
/// - data: `Data` returned from the server, if any.
/// - error: `Error` produced by Alamofire or the underlying `URLSession` during the request.
///
/// - Returns: The `SerializedObject`.
/// - Throws: Any `Error` produced during serialization.
func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> SerializedObject
}
复制代码
public protocol ResponseSerializer: DataResponseSerializerProtocol & DownloadResponseSerializerProtocol {
复制代码
dataRequest ---> finish ---> responseSerializer() --->DecodableResponseSerializer -->serialize
最终最主要的代码
data = try dataPreprocessor.preprocess(data)
do {
return try decoder.decode(T.self, from: data)
} catch {
throw AFError.responseSerializationFailed(reason: .decodingFailed(error: error))
}
复制代码