swift3 模型转字典(JSON)
Posted WoodBear009
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swift3 模型转字典(JSON)相关的知识,希望对你有一定的参考价值。
项目中最近需要将一个复杂的对象转成JSON,于是就利用Mirror写了一个模型转字典的通用方法,应该可以满足大部分使用场景下的需求了
函数实现:
func convertToDictNesting(obj: Any, remainFeild: [String]? = nil, replace: (((label: String, value: Any)) -> (String, Any))? = nil) -> [String: Any]
var dict: [String: Any] = [:]
var children: [Mirror.Child] = []
if let superChildren = Mirror(reflecting: obj).superclassMirror?.children
children.append(contentsOf: superChildren)
children.append(contentsOf: Mirror(reflecting: obj).children)
for child in children
if let key = child.label
if let remainFeild = remainFeild, !remainFeild.contains(key)
continue
let subMirror = Mirror(reflecting: child.value)
if let displayStyle = subMirror.displayStyle, displayStyle == .optional
if subMirror.children.isEmpty
continue
//解析类型属性
let subDict = convertToDictNesting(obj: child.value, remainFeild: remainFeild, replace: replace)
if subDict.isEmpty
if let replaceReturn = replace?((key, child.value))
if !replaceReturn.0.isEmpty
if let aryValue = replaceReturn.1 as? [Any]
var dictAry: [Any] = []
for value in aryValue
let subDict = convertToDictNesting(obj: value, remainFeild: remainFeild, replace: replace)
if subDict.isEmpty
dictAry.append(value)
else
dictAry.append(subDict)
dict[replaceReturn.0] = dictAry
else
dict[replaceReturn.0] = replaceReturn.1
else
if let aryValue = child.value as? [Any]
var dictAry: [Any] = []
for value in aryValue
let subDict = convertToDictNesting(obj: value, remainFeild: remainFeild, replace: replace)
if subDict.isEmpty
dictAry.append(value)
else
dictAry.append(subDict)
dict[key] = dictAry
else
dict[key] = child.value
else
//非基础数据类型暂时只支持label替换
if let replace = replace?((key, child.value))
if !replace.0.isEmpty
if let someDict = subDict["some"]
dict[replace.0] = someDict
else
dict[replace.0] = subDict
else
if let someDict = subDict["some"]
dict[key] = someDict
else
dict[key] = subDict
return dict
使用示例
1.基本使用
enum Sex
case male
case female
class People
let name: String
let sex: Sex
let age: Int
init(name: String, sex: Sex = .male, age: Int)
self.name = name
self.sex = sex
self.age = age
class Teacher: People
let salary: Float
var title: String?
init(name: String, sex: Sex = .male, age: Int, salary: Float, title: String? = nil)
self.salary = salary
self.title = title
super.init(name: name, sex: sex, age: age)
class Student: People
let id: String
init(name: String, sex: Sex = .male, age: Int, id: String)
self.id = id
super.init(name: name, sex: sex, age: age)
class Class
let classId: String
let name: String
var teacher: Teacher?
var students: [Student]?
init(classId: String, name: String)
self.classId = classId
self.name = name
let class1 = Class(classId: "1", name: "数学")
let mathTeacher = Teacher(name: "mm", age: 30, salary: 100)
mathTeacher.title = "特级教师"
class1.teacher = mathTeacher
let student1 = Student(name: "ww", age: 11, id: "1")
let student2 = Student(name: "zz", age: 11, id: "2")
let student3 = Student(name: "yy", age: 11, id: "3")
class1.students = [student1, student2, student3]
let class1Dict = convertToDictNesting(obj: class1)
print(class1Dict)
let class2 = Class(classId: "1", name: "语文")
let chineseTeacher = Teacher(name: "ll", age: 35, salary: 100)
class2.teacher = chineseTeacher
class2.students = [student1, student2]
let class2Dict = convertToDictNesting(obj: class2)
print(class2Dict)
2.remainFeild参数的使用
在有些情况下我们可能不希望转换对象的所有属性,这时可以通过remainFeild参数进行属性的筛选let class1Dict = convertToDictNesting(obj: class1, remainFeild: ["classId", "name", "teacher", "sex", "title", "some"])
print(class1Dict)
print("\\n")
上面的代码仅转换了classId、name、teacher、sex等几个remainFeild中声明的属性 说明:1.如果保留的属性中包含可选型属性,remainFeild中需要加入"some"字段,否则可选型属性无法解析 2.Class、Student、Teacher都有name属性,如果仅想保留Class的name字段,过滤掉Student、Teacher的name属性,目前是暂不支持的。其实代码上我这边有过实现,可以针对不同的对象单独设置过滤字段,但在实际使用中发现这样会让使用成本过高,一旦对象结构复杂或是嵌套很深时,使用者需要对每一个涉及的对象都进行过滤设置,十分麻烦,要考虑的细节太多,于是就保留下了这种相对“无脑”式的过滤方式。不过好在最终生成的是字典,多余的字段只要使用者不去主动访问,一般也不会造成什么影响
3.replace字段的使用
目前转换后的字典规则是:key=属性名,value=属性值。但有些情况下我们可能需要对key进行重命名,或是对value进行类型的转换或加入一些处理,这种情况下则可以借助replace参数let class1Dict = convertToDictNesting(obj: class1) (origin) -> (String, Any) in
switch origin.label
case "salary" :
return ("salary", "\\(origin.value)元")
case "sex" :
if let sex = origin.value as? Sex
return ("sex", sex.rawValue)
return origin
case "classId" :
return ("ClassID", origin.value)
default :
return origin
print(class1Dict)
说明:1.转换同样只认属性不认对象,比较"无脑",主要是我们的项目中没有这个需求,如果你有相应需求,可以在replace闭包中将对象(obj)返回,这样调用者就可以针对不同对象做更有针对性的转换了。
4.其他说明
1.计算型属性无法被解析转换 2.默认情况下nil是会被过滤掉的,但是如果你有一个属性声明为了!,如class Class
var testString: String!
但自始至终你又没有给它赋过任何值,在这种情况下nil是无法被过滤掉的,不过如果出现了这种情况,你更应该去排查一下代码,为什么会有这种危险的情况出现
最后,字典转JSON
func toJSONString(dict: [AnyHashable: Any]) -> String
do
let data = try JSONSerialization.data(withJSONObject: dict, options: [])
let str = String(data: data, encoding: .utf8) ?? ""
return str
catch _
return ""
以上是关于swift3 模型转字典(JSON)的主要内容,如果未能解决你的问题,请参考以下文章