口腔溃疡缺什么维生素| 于谦为什么加入国民党| 达芬奇是干什么的| 六味地黄丸是治什么病| 阑尾炎可以吃什么水果| 为什么七星瓢虫是益虫| 法西斯是什么意思啊| 小节是什么意思| 羊水污染对宝宝有什么影响| 1933年属什么| 阳贵是什么意思| 15号是什么日子| 踩雷是什么意思| 桂花是什么季节开的| 做梦手机坏了什么预兆| 孔雀开屏寓意什么意思| 嗓子不舒服做什么检查| 片是什么| 秦皇岛为什么叫秦皇岛| 巨蟹女喜欢什么样的男生| 长痘痘用什么药| 鹿茸泡酒有什么功效| 双侧乳腺小叶增生是什么意思| 什么花晚上开| 宇五行属什么| 为什么没人穿卡帕| 什么是铅| 回头是岸是什么意思| 一国两制什么时候提出的| 草莓像什么| 长期贫血会导致什么严重后果| 坐骨神经吃什么药| 狗为什么会吐| 三叉神经痛吃什么药效果好| 五个月的宝宝能吃什么辅食| 什么是龙骨| 一条条什么| 泌尿系统由什么组成| 青少年额头长痘痘是什么原因| 散光是什么症状| 乌灵胶囊有什么副作用| 什么梨| 薇字五行属什么| 六月初一什么日子| 看见双彩虹有什么征兆| 吐鲁番为什么那么热| 谷氨酰胺是什么| 四季不安痣是什么意思| 机不可失的下一句是什么| 星期一左眼皮跳是什么预兆| 霜降出什么生肖| 衄血是什么意思| 喝酒前吃什么保护胃| 为什么新生儿有胎记| 大便出血是什么原因引起的| 啾是什么意思| 同型半胱氨酸查什么| 3月11日是什么星座| 乾五行属什么| 祛湿是什么意思| 社畜什么意思| 衤字旁的字与什么有关| 梦见自己在飞是什么征兆| 腊八节吃什么| 什么是轻断食| 08是什么生肖| 泵头是什么| 麻长什么样子图片| 气喘吁吁什么意思| 2020年是属什么生肖| 优甲乐是什么药| 尿频尿急尿不尽吃什么药| 夏天什么颜色最防晒| 尿潴留是什么症状| 打狂犬疫苗不能吃什么| 五台山在什么地方| 霉菌性阴炎用什么药好得快| 十五年是什么婚| 干咳吃什么药最有效| 守宫是什么动物| 格格是什么意思| 表哥的女儿叫什么| 为什么不想上班| 绿豆与什么食物相克| 双子座爱吃什么| 盐酸苯海索片治什么病| roca是什么品牌| 雪里红是什么菜| 朱元璋长什么样| 灰指甲是什么症状| 广东是什么气候| 睡眠不好会引起什么症状| 时间是什么| 卖酒需要办理什么证| 解落三秋叶的解是什么意思| 凉拌菜用什么醋最好| 高考移民是什么意思| 慢性非萎缩性胃炎伴糜烂吃什么药| 思源名字的寓意是什么| 低血钾是什么原因引起的| 糖吃多了有什么危害| 人类什么时候灭绝| 区委书记是什么级别| 趋光性是什么意思| 攻击的近义词是什么| 养肝护肝吃什么最好| 胃热是什么原因引起的| 经常打喷嚏是什么原因| 鸡飞狗跳是指什么生肖| 女人梦见棺材是什么征兆| 私联是什么意思| 维生素B1有什么副作用| 什么是pid| 酌情处理是什么意思| 碱性磷酸酶高吃什么药| 女人梦见蛇是什么预兆| 五月二十八是什么日子| 儿童流黄鼻涕吃什么药| 月经量特别少是什么原因| 开户名是什么| 什么原因导致卵巢早衰| 体检去医院挂什么科| 什么样的人容易得脑梗| prince是什么牌子| 机翻是什么意思| 腋窝淋巴结肿大挂什么科| 一失足成千古恨是什么意思| 张卫健属什么生肖| 褥疮用什么药膏最好| 老年人便秘吃什么药| 什么样的伤口算开放性| 诛仙讲的是什么故事| 什么桥下没有水| 大汗淋漓是什么意思| 腰困是什么原因| 燕窝什么人不适合吃| 八爪鱼是什么意思| 车抛锚是什么意思| 麾下什么意思| 4月4日是什么星座| 家里出现蜈蚣是什么预兆| 甲状腺3类是什么意思| 身上痒但是什么都没有| 灵魂伴侣是指什么意思| 最好的止疼药是什么药| 什么是体位性低血压| INS什么意思| 月经期间可以吃什么水果| 什么水果是降火的| 丛林之王是什么动物| 芭蕉和香蕉有什么区别| 八十岁是什么寿| 北京市副市长是什么级别| 世态炎凉是什么意思| 裤裙搭配什么上衣好看| 忘川是什么意思| 年柱亡神是什么意思| 蚂蚁上树什么姿势| 槟榔吃多了有什么危害| 兰花是什么季节开的| 彩金是什么金| 89属什么| 认命是什么意思| 脊髓炎吃什么药| 防微杜渐是什么意思| 普瑞巴林是什么药| 一个骨一个宽是什么字| 小朋友膝盖疼是什么原因| 态度是什么意思| 秦二世为什么姓胡| 一片哗然是什么意思| 四叶草是什么意思| 不什么其什么| 明前茶什么意思| 平的反义词是什么| 什么叫尿毒症| 疱疹用什么药| 处暑是什么节气| 为什么一低头就晕| 偏执什么意思| 月经前一周失眠是什么原因| 尿酸高看什么科| 较重闭合性跌打损伤是什么意思| 0.5是什么意思| 属牛本命佛是什么佛| 天庭是什么意思| 做爱是什么感觉| 扁桃体结石是什么原因引起的| 7月24日是什么日子| 痔疮有什么特效药| 紧急避孕药什么时候吃| 口腔溃疡缺什么| 第四个手指叫什么| 鸡精和味精有什么区别| 有什么别有病| 高血压是什么意思| 为什么总放屁| 紧急避孕药什么时候吃最好| 伏吟是什么意思| 夜来香是什么花| 吃了鸡蛋不能吃什么| 十点多是什么时辰| 类风湿关节炎吃什么药效果好| 四月二十一是什么星座| 梦见办丧事是什么兆头| jbl是什么牌子| 抗宫炎软胶囊主要治什么| 聊胜于无什么意思| 七月半吃什么| 味精吃多了有什么危害| 什么争什么斗| 黑头发有什么好处脑筋急转弯| 豆工念什么| 湿气重是什么原因造成的| 心脏传导阻滞是什么意思| xgrq是什么烟| ps医学上是什么意思| 爱什么稀罕| 去心火喝什么茶好| 间质性改变是什么意思| 身上老是痒是什么原因| 10月12号是什么星座| 保险凭证号是什么| 肠系膜淋巴结肿大吃什么药| 异地补办身份证需要什么手续| 泔水是什么意思| 耳根有痣代表什么| 属相是什么| 中性粒细胞低吃什么药| 什么是绝对值| 鸡男配什么属相最好| 胆碱能性荨麻疹吃什么药| 楞头青是什么意思| 上环什么时候去最合适| 济南有什么特产| 牛排用什么油煎好吃| 睡醒口干口苦是什么原因| 八嘎呀路是什么意思| 梦见很多棺材是什么征兆| 猫哭了代表什么预兆| 浅卡其色裤子配什么颜色上衣| 三焦指的是什么器官| 鹅蛋炒什么好吃| 阑尾炎痛起来什么感觉| 植物光合作用产生什么| 苹果醋有什么好处| 乐意是什么意思| 扭转乾坤是什么生肖| 素女经是什么| 什么东西醒酒| BCG是什么意思| 老人经常头晕是什么原因引起的| 心口窝疼挂什么科| 什么东西在倒立之后会增加一半| 脸上起红疙瘩是什么原因| 确认妊娠是什么意思啊| 75岁属什么| 子午相冲是什么生肖| 酥油茶是什么做的| 头发不干就睡觉有什么危害| 炸薯条用什么淀粉| 血常规是什么意思| 荔枝为什么上火| 碱吃多了有什么危害| 百度

【KakaJSON手册】01_JSON转Model_01_基本用法

百度 事实上,让无所遁形的就是颗粒粒径检测技术,其已被广泛应用于工业、化学、环境安全等诸多领域。

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

  • Swift内置了一套Codable机制,可以用于JSON转Model。对于一些简单的模型结构,还是挺好用,但一旦牵扯到复杂的模型结构、一些个性化的需求(比如KeyMapping、类型不匹配时的转换处理、自定义解析规则等),Codable就不太能友善地完成任务了。
  • 为了解决上述问题,我编写了一套纯Swift实现的JSON与Model互相转换的框架:KakaJSON,本人非常喜欢龙珠,框架取名自Kaka Rotto(卡卡罗特,孙悟空)
  • KakaJSON通过了大量的单元测试用例(目前有80多个测试用例,未来会增加到上百个测试用例,也非常欢迎大家提供各种应用场景和测试用例),应对各种常用的数据场景,对外提供了一些友善易用、扩展性强、可高度个性化定制需求的接口,内置了Metedata缓存等机制,加快转换速度。
  • 本教程是为了让大家能够快速上手KakaJSON,挖掘它内部的各种功能,发挥它的最大威力。未来也可能会推出一些源码分析的文章。
  • 本文是《KakaJSON手册》系列文章的第一篇

最简单的Model

import KakaJSON

// ① 让模型类型遵守`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 cat1 = json.kj.model(Cat.self)
XCTAssert(cat1.name == "Miaomiao")
XCTAssert(cat1.weight == 6.66)

// 或者也可以调用一个全局函数来完成JSON转模型
let cat2 = model(from: json, Cat.self)

Type Variable

// 有时类型可能是个变量,比如
var type: Convertible.Type = Cat.self

// 调用带有type参数的方法即可
// 由于传入的类型是Convertible.Type变量,因此返回值类型是Convertible,到时根据需求强制转换成自己想要的类型
let cat1 = json.kj.model(type: type) as? Cat

// 或者调用全局函数
let cat2 = model(from: json, type: type) as? Cat

Class类型

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

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

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
    }
}

继承

// 有继承的情况也是照常使用即可

class Person: Convertible {
    var name: String = ""
    var age: Int = 0
    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)

let属性

// KakaJSON也支持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 = ...
let cat = json.kj.model(Cat.self)

NSNull

struct Cat: Convertible {
    var weight: Double = 0.0
    var name: String = "xx"
    var data: NSNull?
}

let json: [String: Any] = [
    "name": NSNull(),
    "weight": 6.6,
    "data": NSNull()
]

let cat = json.kj.model(Cat.self)
// 转换失败,保留默认值
XCTAssert(cat.name == "xx")
XCTAssert(cat.weight == 6.6)
XCTAssert(cat.data == NSNull())

JSONString

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

// 跟JSON的用法是一样的
let cat1 = jsonString.kj.model(Cat.self)
let cat2 = model(from: jsonString, Cat.self)

var type: Convertible.Type = Cat.self
let cat3 = jsonString.kj.model(type: type) as? Cat
let cat4 = model(from: jsonString, type: type) as? Cat

JSONData

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

// 跟JSON的用法是一样的
let cat1 = jsonData.kj.model(Cat.self)
let cat2 = model(from:jsonData, Cat.self)

var type: Convertible.Type = Cat.self
let cat3 = jsonData.kj.model(type: type) as? Cat
let cat4 = model(from: jsonData, type: type) as? Cat

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)
XCTAssert(person.car?.name == "BMW7")
XCTAssert(person.books?[1].name == "Data Structure And Algorithm")
XCTAssert(person.dogs?["dog0"]?.name == "Larry")

Model嵌套2

// Set也能像Array那样支持Model嵌套

// Set要求存放的元素遵守Hashable协议
struct Book: Convertible, Hashable {
    var name: String = ""
    var price: Double = 0.0
}

struct Person: Convertible {
    var name: String = ""
    var books: Set<Book>?
}

let json: [String: Any] = [
    "name": "Jack",
    "books": [
        ["name": "Fast C++", "price": 666.6]
    ]
]

let person = json.kj.model(Person.self)
XCTAssert(person.name == "Jack")

XCTAssert(person.books?.count == 1)
// 从Set中取出来是个Book模型
let book = person.books?.randomElement()
XCTAssert(book?.name == "Fast C++")
XCTAssert(book?.price == 666.6)

Model嵌套3

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)
XCTAssert(person.name == "Jake")
// 保留默认值
XCTAssert(person.car.name == "Bently")
// 从json解析过来的值
XCTAssert(person.car.price == 305.6)
// 从json解析过来的值
XCTAssert(person.dog.name == "Wangwang")
// 保留默认值
XCTAssert(person.dog.age == 5)

递归

class Person: Convertible {
    var name: String = ""
    var parent: Person?
    required init() {}
}

let json: [String: Any] = [
    "name": "Jack",
    "parent": ["name": "Jim"]
]

let person = json.kj.model(Person.self)
XCTAssert(person.name == "Jack")
XCTAssert(person.parent?.name == "Jim")

泛型

struct NetResponse<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 response1 = json1.kj.model(NetResponse<User>.self)
XCTAssert(response1?.msg == "Success")
XCTAssert(response1?.code == 200)
XCTAssert(response1?.data?.nickName == "KaKa")
XCTAssert(response1?.data?.id == "213234234")

let json2 = """
{
    "data": [
        {"price": "6199", "name": "iPhone XR"},
        {"price": "8199", "name": "iPhone XS"},
        {"price": "9099", "name": "iPhone Max"}
    ],
    "msg": "Success",
    "code" : 200
}
"""
let response2 = json2.kj.model(NetResponse<[Goods]>.self)
XCTAssert(response2?.msg == "Success")
XCTAssert(response2?.code == 200)
XCTAssert(response2?.data?.count == 3)
XCTAssert(response2?.data?[0].price == 6199)
XCTAssert(response2?.data?[0].name == "iPhone XR")
XCTAssert(response2?.data?[1].price == 8199)
XCTAssert(response2?.data?[1].name == "iPhone XS")
XCTAssert(response2?.data?[2].price == 9099)
XCTAssert(response2?.data?[2].name == "iPhone Max")

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)
XCTAssert(cars[1].name == "Bently")

// 同样的还有其他方式
let cars2 = modelArray(from: json, Car.self)
var type: Convertible.Type = Car.self
let cars3 = json.kj.modelArray(type: type) as? [Car]
let cars4 = modelArray(from: json, type: type) as? [Car]

// 另外,jsonString转为Model数组,也是如此简单
let jsonString = "...."
let cars5 = jsonString.kj.modelArray(Car.self)
let cars6 = modelArray(from: jsonString, Car.self)
let cars7 = jsonString.kj.modelArray(type: type) as? [Car]
let cars8 = modelArray(from: jsonString, type: type) as? [Car]

字典嵌套Model数组

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

struct Person: Convertible {
    var name: String = ""
    var books: [String: [Book?]?]?
}

let name = "Jack"
let mobileBooks = [
    (name: "iOS", price: 10.5),
    (name: "Android", price: 8.5)
]
let serverBooks = [
    (name: "Java", price: 20.5),
    (name: "Go", price: 18.5)
]

let json: [String: Any] = [
    "name": name,
    "books": [
        "mobile": [
            ["name": mobileBooks[0].name, "price": mobileBooks[0].price],
            ["name": mobileBooks[1].name, "price": mobileBooks[1].price]
        ],
        "server": [
            ["name": serverBooks[0].name, "price": serverBooks[0].price],
            ["name": serverBooks[1].name, "price": serverBooks[1].price]
        ]
    ]
]

let person = json.kj.model(Person.self)
XCTAssert(person.name == name)
let books0 = person.books?["mobile"]
XCTAssert(books0??.count == mobileBooks.count)
for i in 0..<mobileBooks.count {
    XCTAssert(books0??[i]?.name == mobileBooks[i].name);
    XCTAssert(books0??[i]?.price == mobileBooks[i].price);
}
let books1 = person.books?["server"]
XCTAssert(books1??.count == serverBooks.count)
for i in 0..<serverBooks.count {
    XCTAssert(books1??[i]?.name == serverBooks[i].name);
    XCTAssert(books1??[i]?.price == serverBooks[i].price);
}

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(json)
XCTAssert(cat.name == "Miaomiao")
XCTAssert(cat.weight == 6.66)

监听

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

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

let name = "Benz"
let age = 100
let car = ["name": name, "age": age].kj.model(Car.self)
// Car - kj_willConvertToModel
// Car - kj_didConvertToModel
XCTAssert(car.name == name)
XCTAssert(car.age == age)

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

// 同样也支持类
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 name = "jack"
let age = 10
let score = 100
let student = ["name": name, "age": age, "score": score].kj.model(Student.self)
// Person - kj_willConvertToModel
// Student - kj_willConvertToModel
// Person - kj_didConvertToModel
// Student - kj_didConvertToModel
XCTAssert(student.name == name)
XCTAssert(student.age == age)
XCTAssert(student.score == score)
posted @ 2025-08-07 17:22  M了个J  阅读(21263)  评论(1)    收藏  举报
骨密度z值是什么意思 火疖子是什么 什么照片看不出照的是谁 念五行属什么 胎儿永久性右脐静脉是什么意思
联通查流量发什么短信 盲从什么意思 家里为什么会进蝙蝠 尽善尽美是什么意思 60年是什么婚
纳财适合做什么 胆囊切除后对身体有什么影响 护照补办需要什么材料 云雾茶是什么茶 老花镜是什么镜
猪油吃多了有什么好处和坏处 五味子什么味道 口干嗓子干是什么原因 木灵念什么 三伏天晒背有什么好处
脚趾头抽筋是什么原因hcv8jop4ns2r.cn 怀孕为什么会流血hcv9jop0ns0r.cn 肚脐眼下方是什么器官hcv9jop4ns7r.cn 西洋参不能和什么一起吃hcv8jop4ns0r.cn 特殊是什么意思hcv7jop9ns4r.cn
脂膜炎是什么原因引起的hcv8jop7ns1r.cn 嘴巴苦苦的是什么原因hcv9jop4ns7r.cn 天地人和是什么意思ff14chat.com 什么是抗氧化hcv7jop7ns1r.cn ipv是什么疫苗hcv8jop6ns9r.cn
女的肾虚是什么原因引起的hcv7jop9ns7r.cn 卡粉是什么原因引起的jasonfriends.com 张飞为什么不救关羽hcv8jop3ns3r.cn 血管钙化是什么意思hcv8jop8ns8r.cn 软卧代软座什么意思hcv9jop4ns7r.cn
误区是什么意思hcv9jop6ns2r.cn 就请你给我多一点点时间是什么歌hcv8jop1ns6r.cn 青少年流鼻血是什么原因引起的hcv9jop3ns2r.cn Ca是什么hcv9jop1ns0r.cn 作怪是什么意思hcv8jop4ns7r.cn
百度