语意
序列化:将数据类型和对象转换成二进制数据
反序列化:将返回的二进制数据转换成对象和其它数据结构
handyJSON
比较好用的JSON转义Model,使用中帮我们把数据转成完成class、struct
**反序列化
//1.声明一个model,继承HandyJSON协议 (枚举继承 HandyJSONEnum协议)
//嵌套:遇到复杂的情况model嵌套model 只需要继承HandyHSON就可以
//继承:只需要父类继承HandyJSON就可以
class Model: HandyJSON {
var int: Int = 2
var doubleOptional: Double?
var stringImplicitlyUnwrapped: String!
required init() {}//如果是class类型,需要加入这一步,不然会报错
}
//2. jsonString 传入需要反序列化的数据
// 获得某个个结点的数据结构 用这个方法:designatedPath
if let animal = Model.deserialize(from: jsonString) {
print(animal)//结果是model类型,需要用点语法获得属性值
}复制代码
**序列化
//1.声明一个model,继承HandyJSON协议
class Bob: HandyJSON {
required init() {}
var int: Int = 30
var fou: Double?
var strinfmp: String?
}
//2.生成对应的model对象
let obje = Bob()
obje.int = 1
obje.fou = 1.1
obje.strinfmp = "hello"
//3.点语法方法,序列化
print(obje.toJSON()!) // dictionary(字典)
print(obje.toJSONString()!) // JSON string(JSON)
print(obje.toJSONString(prettyPrint: true)!) // pretty JSON string (映射json字符串)复制代码
**自定义(适用于更改model内属性的名称,解析麻烦的数据结构,如元祖类型数据)
//1.声明一个model,继承HandyJSON协议
class Cat: HandyJSON {
var id: Int64!
var name: String!
var parent: (String, String)?
required init() {}
//2.实现函数 mapping方法
func mapping(mapper: HelpingMapper) {
//3. 使用specify(property:)自定义字段内容
mapper.specify(property: &id, name: "cat_id")
mapper.specify(property: &parent) { (rawString) -> (String, String) in
let parentNames = rawString.characters.split{$0 == "/"}.map(String.init)
return (parentNames[0], parentNames[1])
}
}
}复制代码
问:为什么mapping函数在继承的子类里不好使?
答:因为Swift类型相关的原因,如果需要在子类里使用mapping函数,那么必须在父类(如果有多层父类,必须在最顶层的父类)里定义一个空的mapping函数,然后在子类去override它。一样情况的还有didFinishMapping函数。
swiftyJSON
方便的获取节点层面的信息,不用担心数组越界并自动对可选类型进行拆包。
**反序列化
(解析本地JSON)
//JSON 转 Data
let data = "{\"doubleOptional\":1.1,\"stringImplicitlyUnwrapped\":\"hello\",\"int\":1}"
if let dataFromString = data.data(using: .utf8, allowLossyConversion: false) {
let json = try! JSON(data: dataFromString)
//获取所有字段的的键值
for (index,obj) in json {
print("\(index) : \(obj)")
}
//获取指定字段头的value
if let dou = json["stringImplicitlyUnwrapped"].string {
print("data \(dou)")
}else {
//打印错误信息
}
}
复制代码
**序列化
//简单数据类型
let json: JSON = "I'm a son"
//Array & Dictionary
var json: JSON = ["name": "Jack", "age": 25, "list": ["a", "b", "c", ["what": "this"]]]
json["list"][3]["what"] = "that"
json["list",3,"what"] = "that"
let path:[JSONSubscriptType] = ["list",3,"what"]
json[path] = "that"复制代码
(获取网络URL解析数据)
//创建URL对象
let url = URL(string:"http://www.hangge.com/getJsonData.php")!
// Alamofire框架
Alamofire.request(url).validate().responseJSON { response in
switch response.result.isSuccess {
case true:
if let value = response.result.value {
let json = JSON(value)
if let number = json[0]["phones"][0]["number"].string {
// 找到电话号码
print("第一个联系人的第一个电话号码:",number)
}
}
case false:
print(response.result.error)
}
}复制代码
Codable(原生)
Apple 在 Swift 4 的 Foundation 的模块中添加了对 JSON 解析成Model的原生支持。
关于 Codable 同时声明了 Decodable 和 Encodable 两个协议,只需要单向处理可以只声明一个。
/// A type that can convert itself into and out of an external representation.
public typealias Codable = Decodable & Encodable复制代码需要满足Codable协议。
需要JSON数据结构和Model对象结构一样,任何差别都会导致解析式失败。
**自定义键值名
struct UserList: Codable {
let userInfos: [UserInfo]
struct UserInfo: Codable {
let userName: String
let age: Int
let bodyHeight: Float
let sex: Bool
private enum CodingKeys: String, CodingKey {
case userName
case age
case bodyHeight = "height"
case sex
}
}
}复制代码
**格式处理
包括属性和方法,可根据自己的需要设置想要的格式。
// outputFormatting属性,提高阅读体验
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted复制代码
**定义可选值
如果JSON的数据结构中,有些 Key - Value 不一定出现,Model中对应的要使用可选类型
例子:
(json)
{
"userInfos": [
{
"userName": "小名",
"age": 18,
"sex": true
},
{
"userName": "小方",
"age": 18,
"height": 162.56,
"sex": false
}
]
}
(model)
struct UserList: Codable {
let userInfos: [UserInfo]
struct UserInfo: Codable {
let userName: String
let age: Int
let height: Float?(可选)
let sex: Bool
}
}复制代码
很久不写swift有些生疏了,最近我也在回顾有关swift的代码,同时也一直在思考swift该如何写,才能得心应手,才能更像一个优雅的工具,因为会用和用好它差别还是挺大的,会一直不断探索iOS的更多有趣性。加油吧!