Swift 字典转模型(KakaJSON) ---1.基本用法

在iOS开发中,后台返回的数据大多是JSON格式,对应地会被网络框架层解析成Swift中的Dictionary、Array。由于数据类型的复杂、字段的繁多,直接使用Dictionary、Array会比较麻烦,比如items[0]["user"]["name"]这样的使用方式,非常不友善,而且没有智能语法提示。所以很多时候会考虑将JSON转换成Model之后再进行操作,会友善很多,比如items[0].user.name。

1.最简单的Model

// ① 让模型类型遵守`Convertible`协议
struct Cat: Convertible {
  var name: String = ""
  var weight: Double = 0.0
}
        
// json也可以是NSDictionary、NSMutableDictionary类型
let json: [String: Any] = [
  "name" : "Miaomiao",
  "weight" : 6.66
]
        
// ② 直接调用json的model方法,传入模型类型,返回模型实例
let cat = json.kj.model(Cat.self)
//let cat = model(from: json, Cat.self)
        
print("name:\(cat.name),  weight:\(cat.weight)")
// name:Miaomiao,  weight:6.66

2.Class类型

class Cat: Convertible {
  var name: String = ""
  var weight: Double = 0.0
            
  // 由于Swift初始化机制的原因,`Convertible`协议强制要求实现init初始化器
  // 这样框架内部才可以完整初始化一个实例
  required init() {}
}
        
let json: [String: Any] = [
  "name" : "老斑",
  "weight" : 6.66
]
        
let cat = json.kj.model(Cat.self)
print("name:\(cat.name),  weight:\(cat.weight)")
// name:老斑,  weight:6.66


// 继承自NSObject的类也是一样的用法
class Person: NSObject, Convertible {
    var name: String = ""
    var age: Int = 0
    
    // 由于NSObject内部已经有init,因此Person算是重载init,需再加上`override`
    required override init() {}
}

let json: [String: Any] = [
    "name" : "李连杰",
    "age" : 67
]

let person = json.kj.model(Person.self)
print("name:\(person.name),  age:\(person.age)")
// name:李连杰,  age:67

struct Dog: Convertible {
    var weight: Double = 0.0
    var name: String = ""
    // 由于编译器自动帮结构体类型生成了一个init初始化器
    // 所以不需要自己再实现init初始化器
}
 
struct Pig: Convertible {
    var weight: Double
    var name: String
    // 如果没有在定义属性的同时指定初始值,编译器是不会为结构体生成init初始化器的
    // 所以需要自己实现init初始化器
    init() {
        name = ""
        weight = 0.0
    }
}

3.继承

class Person: Convertible {
    var name: String = ""
    var age: Int = 0
    
    // 由于NSObject内部已经有init,因此Person算是重载init,需再加上`override`
    required init() {}
}
class Student: Person {
    var score: Int = 0
    var no: String = ""
}

let json: [String: Any] = [
    "name": "jack",
    "age": 18,
    "score": 98,
    "no": "9527"
]

let student = json.kj.model(Student.self)
print("name:\(student.name),  age:\(student.age),  score:\(student.score),  no:\(student.no)")
// name:jack,  age:18,  score:98,  no:9527

4.let属性

struct Cat: Convertible {
    // 测试表明:在真机release模式下,对数字类型的let限制比较严格
    // 值虽然修改成功了(可以打印Cat结构体发现weight已经改掉了),但get出来还是0.0
    // 所以建议使用`private(set) var`取代`let`
    private(set) var weight: Double = 0.0
    let name: String = ""
}
        
let json: [String: Any] = [
    "name" : "Miaomiao",
    "weight" : 6.66
]

let cat = json.kj.model(Cat.self)
print("name:\(cat.name),  weight:\(cat.weight)")
// name:Miaomiao,  weight:6.66

5. JSONString

struct Cat: Convertible {
    var weight: Double = 0.0
    var name: String = ""
}

// jsonString也可以是NSString、NSMutableString类型     
let jsonString = """
{
    "name": "Miaomiao",
    "weight": 6.66
}
"""

let cat = jsonString.kj.model(Cat.self)
guard let cat1 = cat else { // guard let 守护
    return
}
print("name:\(cat1.name),  weight:\(cat1.weight)")
// name:Miaomiao,  weight:6.66

6. JSONData

struct Cat: Convertible {
    var weight: Double = 0.0
    var name: String = ""
}

// jsonData也可以是NSData、NSMutableData类型     
let jsonData = """
{
    "name": "Miaomiao",
    "weight": 6.66
}
""".data(using: .utf8)!

let cat = jsonData.kj.model(Cat.self)
guard let cat1 = cat else {
    return
}
print("name:\(cat1.name),  weight:\(cat1.weight)")
// name:Miaomiao,  weight:6.66

7.Model嵌套1

// 让需要进行转换的模型都遵守`Convertible`协议

struct Book: Convertible {
    var name: String = ""
    var price: Double = 0.0
}

struct Car: Convertible {
    var name: String = ""
    var price: Double = 0.0
}

struct Dog: Convertible {
    var name: String = ""
    var age: Int = 0
}

struct Person: Convertible {
    var name: String = ""
    var car: Car?
    var books: [Book]?
    var dogs: [String: Dog]?
}
        
let json: [String: Any] = [
    "name": "Jack",
    "car": ["name": "BMW7", "price": 105.5],
    "books": [
        ["name": "Fast C++", "price": 666.6],
        ["name": "Data Structure And Algorithm", "price": 1666.6]
    ],
    "dogs": [
        "dog0": ["name": "Larry", "age": 5],
        "dog1": ["name": "ErHa", "age": 2]
    ]
]

let person = json.kj.model(Person.self)
        
guard let car = person.car,
    let books = person.books,
    let dogs = person.dogs else {
    return
}

print("name:\(person.name),  car:\(car)")

for book: Book in books {
    print("book:\(book)")
}
for (key, value) in dogs {
    print("key:\(key) value:\(value)")
}
/*
name:Jack,  car:Car(name: "BMW7", price: 105.5)
book:Book(name: "Fast C++", price: 666.6)
book:Book(name: "Data Structure And Algorithm", price: 1666.6)
key:dog0 value:Dog(name: "Larry", age: 5)
key:dog1 value:Dog(name: "ErHa", age: 2)
*/

8.Model嵌套2

struct Car: Convertible {
    var name: String = ""
    var price: Double = 0.0
}

class Dog: Convertible {
    var name: String = ""
    var age: Int = 0
    required init() {}
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

struct Person: Convertible {
    var name: String = ""
    // 如果你的模型有默认值,KakaJSON内部不会再创建新的模型
    // 会直接重复利用你创建的模型,节省内存分配和初始化的开销
    var car: Car = Car(name: "Bently", price: 106.5)
    var dog: Dog = Dog(name: "Larry", age: 5)
}
        
let json: [String: Any] = [
    "name": "Jake",
    "car": ["price": 305.6],
    "dog": ["name": "Wangwang"]
]

let person = json.kj.model(Person.self)
print("name:\(person.name),  car:\(person.car)")
print("dog: ----> name:\(person.dog.name)  age:\(person.dog.age)")
/*
name:Jake,  car:Car(name: "Bently", price: 305.6)
dog: ----> name:Wangwang  age:5
*/

9.泛型

struct NetRespones<Element>: Convertible {
    let data: Element? = nil
    let msg: String = ""
    private(set) var code: Int = 0
    
}

struct User: Convertible {
    let id: String = ""
    let nickName: String = ""
}

struct Goods: Convertible {
    private(set) var price: CGFloat = 0.0
    let name: String = ""
}

let json1 = """
    {
    "data": {"nickName": "KaKa", "id": 213234234},
    "msg": "Success",
    "code" : 200
    }
    """
let response = json1.kj.model(NetRespones<User>.self)

guard let response1 = response  else {
    return
}
print("response: msg: \(response1.msg)  code:\(response1.code)  data:\(response1.data ?? User())")
// response: msg: Success  code:200  data:User(id: "213234234", nickName: "KaKa")

10.Model数组

struct Car: Convertible {
    var name: String = ""
    var price: Double = 0.0
}

// json数组可以是Array<[String: Any]>、NSArray、NSMutableArray
let json: [[String: Any]] = [
    ["name": "Benz", "price": 98.6],
    ["name": "Bently", "price": 305.7],
    ["name": "Audi", "price": 64.7]
]

// 调用json数组的modelArray方法即可
let cars = json.kj.modelArray(Car.self)

for car: Car in cars {
    print("car: \(car)")
}
print("----------------------------")

for (index, value) in cars.enumerated() {
    print("index: \(index)   value: \(value)")
}
/*
car: Car(name: "Benz", price: 98.6)
car: Car(name: "Bently", price: 305.7)
car: Car(name: "Audi", price: 64.7)
----------------------------
index: 0   value: Car(name: "Benz", price: 98.6)
index: 1   value: Car(name: "Bently", price: 305.7)
index: 2   value: Car(name: "Audi", price: 64.7)
*/

11. Convert

// 如果你想把JSON数据转换到原本已经创建好的模型实例上,可以使用convert方法

struct Cat: Convertible {
    var name: String = ""
    var weight: Double = 0.0
}

let json: [String: Any] = [
    "name": "Miaomiao",
    "weight": 6.66
]

var cat = Cat()
// .kj_m是.kj的mutable版本,牵扯到修改实例本身都是.kj_m开头
cat.kj_m.convert(from: json)
print("name: \(cat.name)   weight\(cat.weight)")
// name: Miaomiao   weight6.66

12. 监听

// 有时候可能想在JSON转模型之前、之后做一些额外的操作
// KakaJSON会在JSON转模型之前调用模型的kj_willConvertToModel方法
// KakaJSON会在JSON转模型之后调用模型的kj_didConvertToModel方法

struct Car: Convertible {
    var name: String = ""
    var age: Int = 0
    
    func kj_willConvertToModel(from json: [String : Any]) {
        print("Car - kj_willConvertToModel")
    }
    
    mutating func kj_didConvertToModel(from json: [String : Any]) {
        print("Car - kj_didConvertToModel")
    }
}

let json: [String: Any] = [
    "name": "Benz",
    "age": 100
]

var car = json.kj.model(Car.self)
print("name: \(car.name)   age: \(car.age)")
/*
Car - kj_willConvertToModel
Car - kj_didConvertToModel
name: Benz   age: 100
*/

/*************************************************************/

// 同样也支持类
class Person: Convertible {
    var name: String = ""
    var age: Int = 0
    required init() {}
    
    func kj_willConvertToModel(from json: [String: Any]) {
        print("Person - kj_willConvertToModel")
    }
    
    func kj_didConvertToModel(from json: [String: Any]) {
        print("Person - kj_didConvertToModel")
    }
}

class Student: Person {
    var score: Int = 0
    
    override func kj_willConvertToModel(from json: [String : Any]) {
        // 如果有必要的话,可以调用super的实现
        super.kj_willConvertToModel(from: json)
        
        print("Student - kj_willConvertToModel")
    }
    
    override func kj_didConvertToModel(from json: [String: Any]) {
        // 如果有必要的话,可以调用super的实现
        super.kj_didConvertToModel(from: json)
        
        print("Student - kj_didConvertToModel")
    }
}

let json: [String: Any] = [
    "name" : "jack",
    "age" : 10,
    "score" : 100
]

let student = json.kj.model(Student.self)
print("name:\(student.name),  age:\(student.age)  score:\(student.score)")
/*
Person - kj_willConvertToModel
Student - kj_willConvertToModel
Person - kj_didConvertToModel
Student - kj_didConvertToModel
name:jack,  age:10  score:100
*/

Swift 字典转模型(KakaJSON) ---2.数据类型
Swift 字典转模型(KakaJSON) ---3.key处理
Swift 字典转模型(KakaJSON) ---4.动态模型
Swift KakaJSON 05.---模型转字典
Swift KakaJSON 06.---Coding/归档/解档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • pyspark.sql模块 模块上下文 Spark SQL和DataFrames的重要类: pyspark.sql...
    mpro阅读 9,422评论 0 13
  • 面向对象三大支柱封装:就是把相关的数据和代码结合成一个有机的整体,形成数据和操作代码的封装体,对外只提供一个可以控...
    WangDavid阅读 1,671评论 0 2
  • title: "Swift 中枚举高级用法及实践"date: 2015-11-20tags: [APPVENTUR...
    guoshengboy阅读 2,535评论 0 2
  • 世界上转换速度最快、使用最简单方便的字典转模型框架 能做什么? MJExtension是一套字典和模型之间互相转换...
    今年27阅读 757评论 0 1
  • 一、iOS 4种JSON数据解析方法详解 2013年09月10日⁄ 综合⁄ 共 9124字⁄ 字号小中大⁄评论关闭...
    lilinjianshu阅读 2,021评论 0 2