Alamofire 数据请求 & 数据解析 (下)

这是我参与更文挑战的第17天,活动详情查看: 更文挑战

img

Alamofire三种数据结果流

  1. response
  2. responseJSON
  3. 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))
        }
复制代码

参考

www.jianshu.com/p/4381fe8e1…

www.jianshu.com/p/acf91a411…

www.jianshu.com/p/4381fe8e1…

猜你喜欢

转载自juejin.im/post/6975162940634857509
今日推荐