Swift 转模型 Codable和ObjectMapper 使

2019-06-29  本文已影响0人  落夏简叶

代码基于Swift4.0.

导读,例子中用到的book.json文件
{
    "title": "War and Peace: A protocol oriented approach to diplomacy",
    "author": "A. Keed Decoder",
    "rating": null,
    "publishedAt": "019-04-16T9:24:37TPM.000Z"
}

使用差异

一、 是否需要映射字段

原生

Mapper

import UIKit
import ObjectMapper

struct XXBook: Mappable {
    // 通过Mapper转模型
    var title: String?
    var author: String?
    var rating: Float?
    var publishedAt: String?
    
    init?(map: Map) {
        
    }
    
    mutating func mapping(map: Map) {
        title            <- map["title"]
        author           <- map["author"]
        rating           <- map["rating"]
        publishedAt      <- map["publishedAt"]
    }
    
}


struct XXXBook: Codable {
    // 通过原生转模型
    var title: String?
    var author: String?
    var rating: Float?
    var publishedAt: String?
}

二、 转模型

原生

//用原生方式转模型
        guard let path = Bundle.main.path(forResource: "book", ofType: "json") else {
            return
        }
        
        guard let jsonData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) else {
            return
        }
        
        let decoder = JSONDecoder()
        if let book = try? decoder.decode(XXXBook.self, from: jsonData) {
            print(book)
        } else {
            print("decode failed")
        }

Mapper

        guard let path = Bundle.main.path(forResource: "book", ofType: "json") else {
            return
        }
        
        guard let jsonData = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) else {
            return
        }
        
        guard let jsonDict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers) else {
            return
        }
        
        guard let json = jsonDict as? [String: Any] else {
            return
        }
        // 用ObjectMapper转模型
        if let book = XXBook(JSON: json) {
            print(book)
        } else {
            print("转模型 failed")
        }
三、 解析字段

原生

XXBook(title: Optional("War and Peace: A protocol oriented approach to diplomacy"), author: Optional("A. Keed Decoder"), rating: nil, publishedAt: Optional("019-04-16T9:24:37TPM.000Z"))
XXBook(title: Optional("War and Peace: A protocol oriented approach to diplomacy"), author: Optional("A. Keed Decoder"), rating: nil, publishedAt: Optional("019-04-16T9:24:37TPM.000Z"))

Mapper

XXXBook(title: Optional("War and Peace: A protocol oriented approach to diplomacy"), author: Optional("A. Keed Decoder"), rating: nil, publishedAt: Optional("019-04-16T9:24:37TPM.000Z"))
decode failed

解析特殊类型差异

一、 日期类型

首先我们需要改造book.json, 和XXBookXXXBook类型
book.json填入正确的时间格式

{
    "title": "War and Peace: A protocol oriented approach to diplomacy",
    "author": "A. Keed Decoder",
    "rating": 5.0,
    "publishedAt": "2018-01-01T00:00:00.000Z"
}

XXBookXXXBookpublishedAt字段改为Date

struct XXBook: Mappable {
    // 通过Mapper转模型
    var title: String?
    var author: String?
    var rating: Float?
    var publishedAt: Date?
    
    init?(map: Map) {
        
    }
    
    mutating func mapping(map: Map) {
        title            <- map["title"]
        author           <- map["author"]
        rating           <- map["rating"]
        publishedAt      <- (map["publishedAt"], ObjectMapperDateTransform())  //mapper转换日期格式 需要自定义变换类需要实现 TransformType 协议。
    }
}

struct ObjectMapperDateTransform: TransformType {
    public typealias Object = Date
    public typealias JSON = String
    public init() {}
    public func transformFromJSON(_ value: Any?) -> Date? {
        if let timeStr = value as? String {
            return XXDataConvert.stringConvertDate(string: timeStr)
            
        }
        return nil
    }
    public func transformToJSON(_ value: Date?) -> String? {
        if let date = value {
            return XXDataConvert.dateConvertString(date: date)
        }
        return nil
    }
}

struct XXXBook: Codable {
    // 通过原生转模型
    var title: String?
    var author: String?
    var rating: Float?
    var publishedAt: Date?
}

struct XXDataConvert {
// 为Mapper作日期转换时抽了几个方法
    static func dateFormatter() -> DateFormatter {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
        dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
        return dateFormatter
    }
    
    static func dateConvertString(date: Date) -> String? {
        let formatter = dateFormatter()
        let date = formatter.string(from: date)
        return date.components(separatedBy: " ").first
    }
    
    static func stringConvertDate(string: String) -> Date? {
        let dateFormat = dateFormatter()
        return dateFormat.date(from: string)
    }
}

原生

decoder.dateDecodingStrategy = .formatted(XXDataConvert.dateFormatter())

Mapper

public protocol TransformType {
    associatedtype Object
    associatedtype JSON

    func transformFromJSON(_ value: Any?) -> Object?
    func transformToJSON(_ value: Object?) -> JSON?
}
二、 枚举类型

XXBookXXXBook 中新增字段 authorGender。 类型是 enum XXGender

enum XXGender: String, Codable {
    case male
    case female
    case other
}

原生

var authorGender: XXGender?

Mapper

authorGender      <- (map["authorGender"], EnumTransform<XXGender>())

总结

在项目中还是结合自己的需求做选择。 像本人负责的项目中,同事无法接受如果后台返回的类型不一致而使对象解析失败,所以坚决选择用ObjectMapper了。

上一篇 下一篇

猜你喜欢

热点阅读