我們知道蘋果從IOS5.0後推出了SDK自帶的JSON解決方案NSJSONSerialization,這是一個非常好用的JSON生成和解析工具,效率也比其他第三方開源項目高。
但用其生成JSON數據有個限制:只能將Foundation對象轉換成JSON。即頂層對象必須是NSArray或者NSDictionary,所有的對象必須是NSString、NSNumber、NSArray、NSDictionary、NSNull的實例。
所以,如果我們想要把自定義類型的數據對象轉成JSON數據,NSJSONSerialization就無能為力了。
1,將自定義對象轉成JSON數據的實現原理(不借助第三方庫)
(1)首先我們使用反射(Reflection)對自定義類型的數據對象中所有的屬性進行遞歸遍歷,生成字典類型的數據並返回。
(2)接著使用NSJSONSerialization就可以把這個字典類型的數據轉換成jSON數據了。
2,比如我們自定義一個的聯系人類
//用戶類
class User {
var name:String = "" //姓名
var nickname:String? //昵稱
var age:Int? //年齡
var emails:[String]? //郵件地址
var tels:[Telephone]? //電話
}
//電話結構體
struct Telephone {
var title:String //電話標題
var number:String //電話號碼
}
3,JSON串生成的功能實現
(1)首先定義一個叫JSON的協議,並對其擴展,實現協議中定義的兩個方法。
toJSONModel():將數據轉成可用的JSON模型。
toJSONString():將數據轉成JSON字符串(其內部會調用前面的toJSONModel()方法)。
(2)將可選類型(Optional),自定義類(User、TeleTelephone),以及基本數據類型進行擴展,使其遵循JSON協議。
同時對於可選類型還要重寫toJSONModel()方法,為的是當可選類型值不存在時返回nil,存在時將其轉成具體類型並序列化。
//自定義一個JSON協議
protocol JSON {
func toJSONModel() -> AnyObject?
func toJSONString() -> String?
}
//擴展協議方法
extension JSON {
//將數據轉成可用的JSON模型
func toJSONModel() -> AnyObject? {
let mirror = Mirror(reflecting: self)
if mirror.children.count > 0 {
var result: [String:AnyObject] = [:]
for case let (label?, value) in mirror.children {
//print("屬性:\(label) 值:\(value)")
if let jsonValue = value as? JSON {
result[label] = jsonValue.toJSONModel()
}
}
return result
}
return self as? AnyObject
}
//將數據轉成JSON字符串
func toJSONString() -> String? {
let jsonModel = self.toJSONModel()
//利用OC的json庫轉換成OC的NSData,
let data : NSData! = try? NSJSONSerialization.dataWithJSONObject(jsonModel!, options: [])
//NSData轉換成NSString打印輸出
let str = NSString(data:data, encoding: NSUTF8StringEncoding)
return str as String?
}
}
//擴展可選類型,使其遵循JSON協議
extension Optional: JSON {
//可選類型重寫toJSONModel()方法
func toJSONModel() -> AnyObject? {
if let x = self {
if let value = x as? JSON {
return value.toJSONModel()
}
}
return nil
}
}
//擴展兩個自定義類型,使其遵循JSON協議
extension User: JSON { }
extension Telephone: JSON { }
//擴展Swift的基本數據類型,使其遵循JSON協議
extension String: JSON { }
extension Int: JSON { }
extension Bool: JSON { }
extension Dictionary: JSON { }
extension Array: JSON { }
4,測試樣例
//創建一個User實例對象
let user1 = User()
user1.name = "hangge"
user1.age = 100
user1.emails = ["[email protected]","[email protected]"]
//添加動畫
let tel1 = Telephone(title: "手機", number: "123456")
let tel2 = Telephone(title: "公司座機", number: "001-0358")
user1.tels = [tel1, tel2]
//輸出json字符串
print(user1.toJSONString()!)
看到控制台輸出如下信息:
原文:Swift - 使用反射將自定義對象數據序列化成JSON數據
格式化後數據如下:
{
"tels": {
"[1]": {
"number": "001-0358",
"title": "公司座機"
},
"[0]": {
"number": "123456",
"title": "手機"
}
},
"age": 100,
"name": "hangge",
"emails": {
"[1]": "[email protected]",
"[0]": "[email protected]"
}
}
使用第三方庫 - JSONKit
1,新建橋街頭文件Bridging-Header.h,並設置到編譯參數裡
1 #include "JSONKit.h"
2,將JSONKit的庫文件導入到項目中來(JSONKit.h和JSONKit.m)
3,這時編譯會發現報錯,這是由於JSONKit庫不支持Objective-C的自動引用計數功能導致。
需要在Build Phases -> Compile Sources -> JSONKit.m,雙擊添加Comipler Flag:-fno-objc-arc 。這樣就完成了不支持自動引用計數的配置。
測試代碼:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
testJson()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func testJson() {
//Swift 字典對象
let user = [
"uname": "user1",
"tel": ["mobile": "138", "home": "010"]
]
//使用 JSONKit 轉換成為 JSON 字符串
let jsonstring = (user as NSDictionary).JSONString()
print(jsonstring);
//由字符串反解析回字典
print(jsonstring.objectFromJSONString() as! NSDictionary)
//使用 JSONKit 轉換成為 NSData 類型的 JSON 數據
let jsondata = (user as NSDictionary).JSONData()
print(jsondata);
//由NSData 反解析回為字典
print(jsondata.objectFromJSONData() as! NSDictionary)
}
}
輸出結果:
{"uname":"user1","tel":{"home":"010","mobile":"138"}}
{
tel = {
home = 010;
mobile = 138;
};
uname = user1;
}
<7b22756e 616d6522 3a227573 65723122 2c227465 6c223a7b 22686f6d 65223a22 30313022 2c226d6f 62696c65 223a2231 3338227d 7d>
{
tel = {
home = 010;
mobile = 138;
};
uname = user1;
}