由於JSON格式的能表達的資料型別是比較有限的,所以伺服器返回的JSON資料有時無法自動轉換成客戶端想要的資料型別。
- 比如伺服器返回的時間可能是個毫秒數
1565480696
,但客戶端想要的是Date
型別 - 再比如客戶端想要的是浮點數
Double
型別,但伺服器返回的可能是字串型別"6.45"
- 再比如客戶端想要的是
Bool
型別,但伺服器返回的可能是"true"
、"1"
、0
- 再比如客戶端想要的是高精度浮點數
NSDecimalNumber
型別,伺服器為了維持精度可能返回字串"0.1234567890123456789"
- 上述不同型別之間的匹配轉換問題,KakaJSON已經內建了常用的解析功能,全部自動轉換,不用做任何額外的配置。本文會介紹一些常見的資料型別匹配、轉換功能。
Int
struct Student: Convertible {
var age1: Int8 = 6
var age2: Int16 = 0
var age3: Int32 = 0
var age4: Int64 = 0
var age5: UInt8 = 0
var age6: UInt16 = 0
var age7: UInt32 = 0
var age8: UInt64 = 0
var age9: UInt = 0
var age10: Int = 0
}
let json: [String: Any] = [
"age1": "suan8fa8",
"age2": "6suan8fa8",
"age3": "6",
"age4": 6.66,
"age5": NSNumber(value: 6.66),
"age6": Int32(6),
"age7": true,
"age8": "FALSE",
"age9": Decimal(6.66),
"age10": NSDecimalNumber(value: 6.66)
]
let student = json.kk.model(Student.self)
// 解析失敗,所以使用預設值6
XCTAssert(student?.age1 == 6)
// 解析到前面的數字6
XCTAssert(student?.age2 == 6)
XCTAssert(student?.age3 == 6)
XCTAssert(student?.age4 == 6)
XCTAssert(student?.age5 == 6)
XCTAssert(student?.age6 == 6)
// true為1,false為0
XCTAssert(student?.age7 == 1)
// 字串true\TRUE\YES\yes都為1,字串false\FALSE\NO\no都為0
XCTAssert(student?.age8 == 0)
XCTAssert(student?.age9 == 6)
XCTAssert(student?.age10 == 6)
Float
struct Student: Convertible {
var height1: Float = 0.0
var height2: Float = 0.0
var height3: Float = 0.0
var height4: Float = 0.0
var height5: Float = 0.0
var height6: Float = 0.0
var height7: Float = 0.0
}
let longFloatString = "0.12345678"
let longFloat: Float = 0.12345678
let json: [String: Any] = [
"height1": "6.66suan8fa8",
"height2": longFloatString,
"height3": NSDecimalNumber(string: longFloatString),
"height4": Decimal(string: longFloatString) as Any,
"height5": 666,
"height6": true,
"height7": "NO"
]
let student = json.kk.model(Student.self)
XCTAssert(student?.height1 == 6.66)
XCTAssert(student?.height2 == longFloat)
XCTAssert(student?.height3 == longFloat)
XCTAssert(student?.height4 == longFloat)
XCTAssert(student?.height5 == 666.0)
// true為1.0,false為0.0
XCTAssert(student?.height6 == 1.0)
// 字串true\TRUE\YES\yes都為1.0,字串false\FALSE\NO\no都為0.0
XCTAssert(student?.height7 == 0.0)
Double
struct Student: Convertible {
var height1: Double = 0.0
var height2: Double = 0.0
var height3: Double = 0.0
var height4: Double = 0.0
var height5: Double = 0.0
var height6: Double = 0.0
var height7: Double = 0.0
}
let longDoubleString = "0.1234567890123456"
let longDouble: Double = 0.1234567890123456
let json: [String: Any] = [
"height1": "6.66suan8fa8",
"height2": longDoubleString,
"height3": NSDecimalNumber(string: longDoubleString),
"height4": Decimal(string: longDoubleString) as Any,
"height5": 666,
"height6": true,
"height7": "NO"
]
let student = json.kk.model(Student.self)
XCTAssert(student?.height1 == 6.66)
XCTAssert(student?.height2 == longDouble)
XCTAssert(student?.height3 == longDouble)
XCTAssert(student?.height4 == longDouble)
XCTAssert(student?.height5 == 666.0)
// true為1.0,false為0.0
XCTAssert(student?.height6 == 1.0)
// 字串true\TRUE\YES\yes都為1.0,字串false\FALSE\NO\no都為0.0
XCTAssert(student?.height7 == 0.0)
Bool
struct Student: Convertible {
var rich1: Bool = false
var rich2: Bool = false
var rich3: Bool = false
var rich4: Bool = false
var rich5: Bool = false
var rich6: Bool = false
}
let json: [String: Any] = [
"rich1": 100,
"rich2": 0.0,
"rich3": "1",
"rich4": NSNumber(value: 0.666),
"rich5": "true",
"rich6": "NO"
]
let student = json.kk.model(Student.self)
// 數值0為false,數值非0都是true
XCTAssert(student?.rich1 == true)
XCTAssert(student?.rich2 == false)
XCTAssert(student?.rich3 == true)
// 0.666是非0,所以為true
XCTAssert(student?.rich4 == true)
// 字串true\TRUE\YES\yes都為true
XCTAssert(student?.rich5 == true)
// 字串false\FALSE\NO\no都為false
XCTAssert(student?.rich6 == false)
String
// 不管是String、NSString,還是NSMutableString,都是等效支援的
struct Student: Convertible {
var name1: String = ""
var name2: String = ""
var name3: NSString = ""
var name4: NSString = ""
var name5: NSMutableString = ""
var name6: NSMutableString = ""
var name7: String = ""
var name8: String = ""
}
let longDecimalString = "0.123456789012345678901234567890123456789"
var longDecimalNumber = NSDecimalNumber(string: longDecimalString)
let json: [String: Any] = [
"name1": 666,
"name2": NSMutableString(string: "777"),
"name3": [1,[2,3],"4"],
"name4": longDecimalNumber,
"name5": 6.66,
"name6": false,
"name7": NSURL(fileURLWithPath: "/users/mj/desktop"),
"name8": URL(string: "http://www.520suanfa.com") as Any
]
let student = json.kk.model(Student.self)
XCTAssert(student?.name1 == "666")
XCTAssert(student?.name2 == "777")
// 這裡相當於預設呼叫了陣列的description方法
XCTAssert(student?.name3 == "[1, [2, 3], \"4\"]")
XCTAssert(student?.name4 == longDecimalString as NSString)
XCTAssert(student?.name5 == "6.66")
XCTAssert(student?.name6 == "false")
XCTAssert(student?.name7 == "file:///users/mj/desktop")
XCTAssert(student?.name8 == "http://www.520suanfa.com")
Decimal
struct Student: Convertible {
var money1: Decimal = 0
var money2: Decimal = 0
var money3: Decimal = 0
var money4: Decimal = 0
var money5: Decimal = 0
var money6: Decimal = 0
}
let longDoubleString = "0.1234567890123456"
let longDouble: Double = 0.1234567890123456
let longDecimalString = "0.123456789012345678901234567890123456789"
var longDecimalNumber = NSDecimalNumber(string: longDecimalString)
let json: [String: Any] = [
"money1": longDouble,
"money2": true,
"money3": longDecimalNumber,
"money4": longDecimalString,
"money5": 666,
"money6": "NO"
]
let student = json.kk.model(Student.self)
XCTAssert(student?.money1 == Decimal(string: longDoubleString))
XCTAssert(student?.money2 == 1)
XCTAssert(student?.money3 == Decimal(string: longDecimalString))
XCTAssert(student?.money4 == Decimal(string: longDecimalString))
XCTAssert(student?.money5 == 666)
XCTAssert(student?.money6 == 0)
NSDecimalNumber
struct Student: Convertible {
var money1: NSDecimalNumber = 0
var money2: NSDecimalNumber = 0
var money3: NSDecimalNumber = 0
var money4: NSDecimalNumber = 0
var money5: NSDecimalNumber = 0
var money6: NSDecimalNumber = 0
}
let longDoubleString = "0.1234567890123456"
let longDouble: Double = 0.1234567890123456
let longDecimalString = "0.123456789012345678901234567890123456789"
var longDecimal = Decimal(string: longDecimalString)!
var longDecimalNumber = NSDecimalNumber(string: longDecimalString)
let json: [String: Any] = [
"money1": longDouble,
"money2": true,
"money3": longDecimal,
"money4": longDecimalString,
"money5": 666.0,
"money6": "NO"
]
let student = json.kk.model(Student.self)
XCTAssert(student?.money1 == NSDecimalNumber(string: longDoubleString))
XCTAssert(student?.money2 == true)
XCTAssert(student?.money2 == 1)
XCTAssert(student?.money3 == longDecimalNumber)
XCTAssert(student?.money4 == longDecimalNumber)
XCTAssert(student?.money5 == 666)
XCTAssert(student?.money6 == false)
XCTAssert(student?.money6 == 0)
NSNumber
struct Student: Convertible {
var money1: NSNumber = 0
var money2: NSNumber = 0
var money3: NSNumber = 0
var money4: NSNumber = 0
var money5: NSNumber = 0
var money6: NSNumber = 0
}
let longDoubleString = "0.1234567890123456"
let longDouble: Double = 0.1234567890123456
let json: [String: Any] = [
"money1": longDouble,
"money2": true,
"money3": Decimal(string: longDoubleString) as Any,
"money4": longDoubleString,
"money5": 666.0,
"money6": "NO"
]
let student = json.kk.model(Student.self)
XCTAssert(student?.money1 == NSNumber(value: longDouble))
XCTAssert(student?.money2 == true)
XCTAssert(student?.money2 == 1)
XCTAssert(student?.money2 == 1.0)
XCTAssert(student?.money3 == NSNumber(value: longDouble))
XCTAssert(student?.money4 == NSNumber(value: longDouble))
XCTAssert(student?.money5 == 666)
XCTAssert(student?.money5 == 666.0)
XCTAssert(student?.money6 == false)
XCTAssert(student?.money6 == 0)
XCTAssert(student?.money6 == 0.0)
Optional
// ?再多都不是問題
struct Student: Convertible {
var rich1: Bool = false
var rich2: Bool? = false
var rich3: Bool?? = false
var rich4: Bool??? = false
var rich5: Bool???? = false
var rich6: Bool????? = false
}
let rich1: Int????? = 100
let rich2: Double???? = 0.0
let rich3: String??? = "0"
let rich4: NSNumber?? = NSNumber(value: 0.666)
let rich5: String? = "true"
let rich6: String = "NO"
let json: [String: Any] = [
"rich1": rich1 as Any,
"rich2": rich2 as Any,
"rich3": rich3 as Any,
"rich4": rich4 as Any,
"rich5": rich5 as Any,
"rich6": rich6
]
let student = json.kk.model(Student.self)
XCTAssert(student?.rich1 == true)
XCTAssert(student?.rich2 == false)
XCTAssert(student?.rich3 == false)
XCTAssert(student?.rich4 == true)
XCTAssert(student?.rich5 == true)
XCTAssert(student?.rich6 == false)
URL
// 支援URL和NSURL
struct Student: Convertible {
var url1: NSURL?
var url2: NSURL?
var url3: URL?
var url4: URL?
}
let url = "http://520suanfa.com/紅黑樹"
let encodedUrl = "http://520suanfa.com/%E7%BA%A2%E9%BB%91%E6%A0%91"
let json: [String: Any] = [
"url1": url,
"url2": URL(string: encodedUrl) as Any,
"url3": url,
"url4": NSURL(string: encodedUrl) as Any
]
let student = json.kk.model(Student.self)
XCTAssert(student?.url1?.absoluteString == encodedUrl)
XCTAssert(student?.url2?.absoluteString == encodedUrl)
XCTAssert(student?.url3?.absoluteString == encodedUrl)
XCTAssert(student?.url4?.absoluteString == encodedUrl)
Data
// 支援NSData和Data
struct Student: Convertible {
var data1: NSData?
var data2: NSData?
var data3: Data?
var data4: Data?
}
let utf8 = String.Encoding.utf8
let str = "RedBlackTree"
let data = str.data(using: utf8)!
let json: [String: Any] = [
"data1": str,
"data2": data,
"data3": str,
"data4": NSData(data: data)
]
let student = json.kk.model(Student.self)
XCTAssert(String(data: (student?.data1)! as Data, encoding: utf8) == str)
XCTAssert(String(data: (student?.data2)! as Data, encoding: utf8) == str)
XCTAssert(String(data: (student?.data3)!, encoding: utf8) == str)
XCTAssert(String(data: (student?.data4)!, encoding: utf8) == str)
Enum
// 遵守一下ConvertibleEnum協議即可支援帶有RawValue的Enum型別
enum Grade: String, ConvertibleEnum {
case perfect = "A"
case great = "B"
case good = "C"
case bad = "D"
}
struct Student: Convertible {
var grade1: Grade = .perfect
var grade2: Grade = .perfect
}
let json: [String: Any] = [
"grade1": "C",
"grade2": "D"
]
let student = json.kk.model(Student.self)
XCTAssert(student?.grade1 == .good)
XCTAssert(student?.grade2 == .bad)
// 換個浮點數試試
enum Grade2: Double, ConvertibleEnum {
case perfect = 8.88
case great = 7.77
case good = 6.66
case bad = 5.55
}
struct Student2: Convertible {
var grade1: Grade2 = .perfect
var grade2: Grade2 = .perfect
var grade3: Grade2 = .perfect
var grade4: Grade2 = .perfect
}
let json2: [String: Any] = [
"grade1": "5.55kaka",
"grade2": 6.66,
"grade3": NSNumber(value: 7.77),
"grade4": NSDecimalNumber(string: "8.88")
]
let student2 = json2.kk.model(Student2.self)
XCTAssert(student2?.grade1 == .bad)
XCTAssert(student2?.grade2 == .good)
XCTAssert(student2?.grade3 == .great)
XCTAssert(student2?.grade4 == .perfect)