This is the 17th day of my participation in Gwen Challenge

Alamofire three data result streams

  1. response
  2. responseJSON
  3. responseDecodable

response

AF.request("http://app.u17.com/v3/appV3_3/ios/phone/comic/boutiqueListNew").response { (response:AFDataResponse) in

The returned data stream must be converted to JSON format through JSONSerialization if it is to be used directly. Then divide the data by manual parsing

1. First convert json data to dict

2. Obtain the String origin from the JSON data

3. If there is a dict in the JSON data, we are converting it once to a dict. The type is String and String because the key-value pair is of that type.

4. Take out the data we need from dict.

5. We can use the data as constants

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)

                    }
            }
Copy the code

responseJSON

AF.request(boutiqueListNewURL, method: .get).responseJSON {response in

The name indicates the format of the directly returned JSON data, as above

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(a)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.")}}Copy the code

responseDecodable

AF.request(boutiqueListNewURL).responseDecodable

Support Decodable protocol, U17Root complies with the Decodable protocol, corresponding to the original data can be converted into Model objects

It’s so nice, you don’t have to worry about data safe types or optional types, you don’t have to do array, dictionary type validation and then parse, you can do it in one step, one line of code.

What you need to do is make sure your JSON objects are Codable. This way, you don’t need to determine whether JSON is nested or common.

 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()
            }
Copy the code

U17Root definition

The U17Root object is actually quite complex, and it is really too tiring to parse manually. Objects nested array, array nested object nested array object nested array object

import Foundation

class U17Root: Codable {
    // If you want your model to simply accept data from a network request without making any changes, it is recommended to use let instead of 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]?
    
    /// This is my custom model property
    var isMoreThanOneComic: Bool = false
    
    enum CodingKeys: String.CodingKey {
        case comicLists = "comicLists"
        case editTime = "editTime"
        case galleryItems = "galleryItems"
    }
    
    init(a){}/* If there are custom attributes in the model that require the full implementation of the Decodable protocol when assigning values to other attributes derived from JSON retrieved from the server, be sure to declare init() {} as well, otherwise you simply don't have a normal initialization method to use 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) // Assign values to user-defined model attributes 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]? }Copy the code

Note ⚠ ️

Make sure that the parse JSON object type and entity type correspond; Pretend that JSON is a map structure and that you define an Array type variable to receive

JSON parsing exception will be reported here!

ResponseDecodable implementation analysis

The responseDecodable implementation way is simple record

/// 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
}
Copy the code
public protocol ResponseSerializer: DataResponseSerializerProtocol & DownloadResponseSerializerProtocol {

Copy the code

dataRequest —> finish —> responseSerializer() —>DecodableResponseSerializer –>serialize

Finally, the most important code

        data = try dataPreprocessor.preprocess(data)
        do {
            return try decoder.decode(T.self, from: data)
        } catch {
            throw AFError.responseSerializationFailed(reason: .decodingFailed(error: error))
        }
Copy the code

reference

www.jianshu.com/p/4381fe8e1…

www.jianshu.com/p/acf91a411…

www.jianshu.com/p/4381fe8e1…