目录

  • 前言
  • 把方法封装到协议的目的
  • 协议代码
  • 编写模型
  • 调用端的代码
  • 对象赚json字符串
  • json字符串转换成模型
  • demo下载地址


前言

之前为了封装URLNavigator路由框架,当要传递控制器的参数的时候,需要用到传json字符串,然后接收的时候再把json字符串转换成对象.所以今天做了这个protocol协议,只要让模型的类遵守协议,然后啥都不用写,就能直接调用方法,为了进一步封装URLNavigator做准备

把方法封装到协议的目的

protocol中,之所以放在protocol而不是class类中的原因是swift不支持多重继承class但是可以多重继承protocol,因为swift不允许继承多个类,如果用户的类继承了我们的类,那么就不能再继承其他类,这样很不方便,但是放到协议里就可以同时继承类和协议,或者继承多个协议和1个类.
假如把我们的协议改成class会报错:Multiple inheritance from classes ‘NSObject’ and ‘TdwModelToJsonString’,意思是“NSObject”和“TdwModelToJsonString”类的多重继承,因为模型的类又继承了NSObject

协议代码

第一段是制作了一个协议,里面添加了getString()方法,目的是把类对象,转换成json字符串,这个字符串,打印出来,是直接你能在网页上线解析的正确格式,支持无线嵌套,继承Codable协议的目的是为了使用里面的JSONEncoder().encode 和 JSONEncoder().encode 和JSONDecoder().decode()这2个方法来编码和解码,这个是swift 4.0以后苹果官方出的json编码解码协议里的方法

import Foundation
//定义ConvertToStringable协议,继承Codable协议,目的是使用JSONEncoder().encode 和JSONDecoder().decode()
public protocol TdwModelToJsonString: Codable{
}
extension TdwModelToJsonString {
    //在协议里面实现方法getString,这样就可以让所有继承ConvertToStringable协议的类,都有默认实现方法getString
    func getString()->String {
        //把按照json编码成流数据
        let data = try? JSONEncoder().encode(self)
        guard let jsonData = data else { return "" }
        //流数据转字符串
        guard let jsonStr = String.init(data: jsonData, encoding: .utf8) else { return "" }
        return jsonStr
    }
}
//写了String类扩展,这样可以String字符串直接.点出来方法
extension String {
    func jsonStrToObject<T>(_ : T.Type) -> T? where T: Codable {
        //字符串转数据流
        guard let data = self.data(using: .utf8) else { return nil }
        //数据流转json字符串
        let str = try? JSONDecoder().decode(T.self, from: data)
        return str
    }
}

编写模型

模型里面需要做的是知识遵守协议TdwModelToJsonString,并且给模型都添加@objc,或者在模型类前面添加@objcMembers,否则运行时候回找不到成员变量.School模型里面只添加了2个成员:name和address .重写description是为了一会打印验证结果方便,因为类对象直接打印只显示实例对象的地址

class School:NSObject, TdwModelToJsonString{//遵守我们的TdwModelToJsonString,其他啥都不用写
    @objc var name:String
    @objc var address:String
    init(name:String,address:String) {
        self.name = name
        self.address = address
    }
    
    override var description:String  {
        return self.dictionaryWithValues(forKeys: ["name","address"]).description
    }
}

Student模型,friends成员变量里面嵌套了学生模型的数组,为了验证我们的方法可以支持嵌套模型的转换,这里没有在4个成员变量前边添加@objc,而是在类前面添加了@objcMembers,这样所有能转换成oc的成员变量都暴露给oc能使用的runtime机制

@objcMembers
class Student:NSObject,Codable,TdwModelToJsonString {//遵守我们的TdwModelToJsonString,其他啥都不用写
    var name:String
    var age:Int
    var school:School
    var friends:[Student] = [Student]()
    init(name:String,age:Int,school:School,friends:[Student]) {
        self.name = name
        self.age = age
        self.school = school
        self.friends = friends
    }
    override var description:String  {
        return self.dictionaryWithValues(forKeys: ["name","age","school","friends"]).description
    }
}

调用端的代码

对象赚json字符串

下面代码1个学校,3个学生,每个学生的 friends是对象数组,我们把对象zhang3转化成json字符串

let QingHua = School(name: "76zhong", address: "song hua jiang bian NO.23")
        let wang5 = Student(name: "wang5", age: 18, school: QingHua, friends: [])
        let li4 = Student(name: "li4", age: 20, school: QingHua, friends: [])
        let zhang3 = Student(name: "zhang3", age: 30,school: QingHua, friends: [li4,wang5])
        
        let str = zhang3.getString()
        print("str=",str)
        jsonStr = str //保存字符串,为了下面json字符串转化成对象使用

打印结果:

str= {“age”:30,“school”:{“name”:“76zhong”,“address”:“song hua jiang bian NO.23”},“friends”:[{“age”:20,“school”:{“name”:“76zhong”,“address”:“song hua jiang bian NO.23”},“friends”:[],“name”:“li4”},{“age”:18,“school”:{“name”:“76zhong”,“address”:“song hua jiang bian NO.23”},“friends”:[],“name”:“wang5”}],“name”:“zhang3”}

把这段字符串放到在线解析json格式的网站查看正确的缩进格式,如下图:

swift5 json转字符串 swift model转json字符串_json字符串


可以看到zhang3对象别正确的转化成json字符串

json字符串转换成模型

这段代码jsonStr是类成员变量,保存了之前的json字符串

//json字符串转换成模型
        guard let obj = jsonStr.jsonStrToObject(Student.self) else{
            return
        }
        print("obj.school.address=",obj.school.address)
        print("obj.friends[0]=",obj.friends[0])
        print("obj.friends[0]=",obj.friends[0])

打印结果: 可以看到obj实例对象里面的成员,都被正确赋值了.

    • obj.school.address= song hua jiang bian NO.23
    • obj.friends[0]= [“age”: 20, “name”: li4, “friends”: <Swift.__EmptyArrayStorage 0x1c9e436e8>(
    )
     , “school”: [“address”: song hua jiang bian NO.23, “name”: 76zhong]]• obj= [“age”: 30, “name”: zhang3, “friends”: <TtGCs23_ContiguousArrayStorageC16tdwModelJsonDemo7Student$ 0x6000005452c0>(
     [“name”: li4, “friends”: <Swift.__EmptyArrayStorage 0x1c9e436e8>()
     , “age”: 20, “school”: [“address”: song hua jiang bian NO.23, “name”: 76zhong]],
     [“school”: [“address”: song hua jiang bian NO.23, “name”: 76zhong], “name”: wang5, “age”: 18, “friends”: <Swift.__EmptyArrayStorage 0x1c9e436e8>()
     ]
     )
     , “school”: [“address”: song hua jiang bian NO.23, “name”: 76zhong]]

    demo下载地址

    请用xcode最新版12.3以上打开运行,否则无法运行
    demo下载地址