【KakaJSON手册】02_JSON转Model_02_数据类型

  • 2019 年 10 月 3 日
  • 筆記

由于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      var age11: 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),      "age11": Date(timeIntervalSince1970: 1565922866)  ]    let student = json.kj.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)  // 字符串trueTRUEYESyes都为1,字符串falseFALSENOno都为0  XCTAssert(student.age8 == 0)  XCTAssert(student.age9 == 6)  XCTAssert(student.age10 == 6)  XCTAssert(student.age11 == 1565922866)

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      var height8: Float = 0.0      var height9: Float = 0.0  }    let json: [String: Any] = [      "height1": "6.66suan8fa8",      "height2": "0.12345678",      "height3": NSDecimalNumber(string: "0.12345678"),      "height4": Decimal(string: "0.12345678") as Any,      "height5": 666,      "height6": true,      "height7": "NO",      "height8": CGFloat(0.12345678),      "height9": Date(timeIntervalSince1970: 1565922866)  ]    let student = json.kj.model(Student.self)  XCTAssert(student.height1 == 6.66)  XCTAssert(student.height2 == 0.12345678)  XCTAssert(student.height3 == 0.12345678)  XCTAssert(student.height4 == 0.12345678)  XCTAssert(student.height5 == 666.0)  // true为1.0,false为0.0  XCTAssert(student.height6 == 1.0)  // 字符串trueTRUEYESyes都为1.0,字符串falseFALSENOno都为0.0  XCTAssert(student.height7 == 0.0)  XCTAssert(student.height8 == 0.12345678)  XCTAssert(student.height9 == 1565922866)

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      var height8: Double = 0.0      var height9: Double = 0.0  }    let json: [String: Any] = [      "height1": "6.66suan8fa8",      "height2": "0.1234567890123456",      "height3": NSDecimalNumber(string: "0.1234567890123456"),      "height4": Decimal(string: "0.1234567890123456") as Any,      "height5": 666,      "height6": true,      "height7": "NO",      "height8": CGFloat(0.1234567890123456),      "height9": Date(timeIntervalSince1970: 1565922866)  ]    let student = json.kj.model(Student.self)  XCTAssert(student.height1 == 6.66)  XCTAssert(student.height2 == 0.1234567890123456)  XCTAssert(student.height3 == 0.1234567890123456)  XCTAssert(student.height4 == 0.1234567890123456)  XCTAssert(student.height5 == 666.0)  // true为1.0,false为0.0  XCTAssert(student.height6 == 1.0)  // 字符串trueTRUEYESyes都为1.0,字符串falseFALSENOno都为0.0  XCTAssert(student.height7 == 0.0)  XCTAssert(student.height8 == 0.1234567890123456)  XCTAssert(student.height9 == 1565922866)

CGFloat

struct Student: Convertible {      var height1: CGFloat = 0.0      var height2: CGFloat = 0.0      var height3: CGFloat = 0.0      var height4: CGFloat = 0.0      var height5: CGFloat = 0.0      var height6: CGFloat = 0.0      var height7: CGFloat = 0.0      var height8: CGFloat = 0.0      var height9: CGFloat = 0.0  }    let json: [String: Any] = [      "height1": "6.66suan8fa8",      "height2": "0.1234567890123456",      "height3": NSDecimalNumber(string: "0.1234567890123456"),      "height4": Decimal(string: "0.1234567890123456") as Any,      "height5": 666,      "height6": true,      "height7": "NO",      "height8": 0.1234567890123456,      "height9": Date(timeIntervalSince1970: 1565922866)  ]    let student = json.kj.model(Student.self)  XCTAssert(student.height1 == 6.66)  XCTAssert(student.height2 == CGFloat(0.1234567890123456))  XCTAssert(student.height3 == CGFloat(0.1234567890123456))  XCTAssert(student.height4 == CGFloat(0.1234567890123456))  XCTAssert(student.height5 == 666.0)  XCTAssert(student.height6 == 1.0)  XCTAssert(student.height7 == 0.0)  XCTAssert(student.height8 == CGFloat(0.1234567890123456))  XCTAssert(student.height9 == CGFloat(1565922866))

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.kj.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)  // 字符串trueTRUEYESyes都为true  XCTAssert(student.rich5 == true)  // 字符串falseFALSENOno都为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 = ""      var name9: String = ""  }    let json: [String: Any] = [      "name1": 666,      "name2": NSMutableString(string: "777"),      "name3": [1,[2,3],"4"],      "name4": NSDecimalNumber(string: "0.123456789012345678901234567890123456789"),      "name5": 6.66,      "name6": false,      "name7": NSURL(fileURLWithPath: "/users/mj/desktop"),      "name8": URL(string: "http://www.520suanfa.com") as Any,      "name9": Date(timeIntervalSince1970: 1565922866)  ]    let student = json.kj.model(Student.self)  XCTAssert(student.name1 == "666")  XCTAssert(student.name2 == "777")  // 这里相当于默认调用了数组的description方法  XCTAssert(student.name3 == "[1, [2, 3], "4"]")  XCTAssert(student.name4 == "0.123456789012345678901234567890123456789")  XCTAssert(student.name5 == "6.66")  XCTAssert(student.name6 == "false")  XCTAssert(student.name7 == "file:///users/mj/desktop")  XCTAssert(student.name8 == "http://www.520suanfa.com")  XCTAssert(student.name9 == "1565922866")

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      var money7: Decimal = 0      var money8: Decimal = 0  }    let json: [String: Any] = [      "money1": 0.1234567890123456,      "money2": true,      "money3": NSDecimalNumber(string: "0.123456789012345678901234567890123456789"),      "money4": "0.123456789012345678901234567890123456789",      "money5": 666,      "money6": "NO",      "money7": CGFloat(0.1234567890123456),      "money8": Date(timeIntervalSince1970: 1565922866)  ]    let student = json.kj.model(Student.self)  XCTAssert(student.money1 == Decimal(string: "0.1234567890123456"))  XCTAssert(student.money2 == 1)  XCTAssert(student.money3 == Decimal(string: "0.123456789012345678901234567890123456789"))  XCTAssert(student.money4 == Decimal(string: "0.123456789012345678901234567890123456789"))  XCTAssert(student.money5 == 666)  XCTAssert(student.money6 == 0)  XCTAssert(student.money7 == Decimal(string: "0.1234567890123456"))  XCTAssert(student.money8 == Decimal(string: "1565922866"))

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      var money7: NSDecimalNumber = 0      var money8: NSDecimalNumber = 0  }    let json: [String: Any] = [      "money1": 0.1234567890123456,      "money2": true,      "money3": Decimal(string: "0.123456789012345678901234567890123456789") as Any,      "money4": "0.123456789012345678901234567890123456789",      "money5": 666.0,      "money6": "NO",      "money7": CGFloat(0.1234567890123456),      "money8": Date(timeIntervalSince1970: 1565922866)  ]    let student = json.kj.model(Student.self)  XCTAssert(student.money1 == NSDecimalNumber(string: "0.1234567890123456"))  XCTAssert(student.money2 == true)  XCTAssert(student.money2 == 1)  XCTAssert(student.money3 == NSDecimalNumber(string: "0.123456789012345678901234567890123456789"))  XCTAssert(student.money4 == NSDecimalNumber(string: "0.123456789012345678901234567890123456789"))  XCTAssert(student.money5 == 666)  XCTAssert(student.money6 == false)  XCTAssert(student.money6 == 0)  XCTAssert(student.money7 == NSDecimalNumber(string: "0.1234567890123456"))  XCTAssert(student.money8 == NSDecimalNumber(string: "1565922866"))

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      var money7: NSNumber = 0      var money8: NSNumber = 0  }    let json: [String: Any] = [      "money1": 0.1234567890123456,      "money2": true,      "money3": Decimal(string: "0.1234567890123456") as Any,      "money4": "0.1234567890123456",      "money5": 666.0,      "money6": "NO",      "money7": CGFloat(0.1234567890123456),      "money8": Date(timeIntervalSince1970: 1565922866)  ]    let student = json.kj.model(Student.self)  XCTAssert(student.money1 == NSNumber(value: 0.1234567890123456))  XCTAssert(student.money2 == true)  XCTAssert(student.money2 == 1)  XCTAssert(student.money2 == 1.0)  XCTAssert(student.money3 == NSNumber(value: 0.1234567890123456))  XCTAssert(student.money4 == NSNumber(value: 0.1234567890123456))  XCTAssert(student.money5 == 666)  XCTAssert(student.money5 == 666.0)  XCTAssert(student.money6 == false)  XCTAssert(student.money6 == 0)  XCTAssert(student.money6 == 0.0)  XCTAssert(student.money7 == NSNumber(value: longDouble))  XCTAssert(student.money8 == NSNumber(value: 1565922866))

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.kj.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,默认会将String转为URLNSURL    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.kj.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,默认会将String转为DataNSData    struct Student: Convertible {      var data1: NSData?      var data2: NSData?      var data3: Data?      var data4: Data?      var data5: NSMutableData?      var data6: NSMutableData?  }    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": NSMutableData(data: data),      "data5": str,      "data6": data  ]    let student = json.kj.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)  XCTAssert(String(data: (student.data5)! as Data, encoding: utf8) == str)  XCTAssert(String(data: (student.data6)! as Data, encoding: utf8) == str)

Date

// 支持Date和NSDate,默认会将毫秒数转为DateNSDate    struct Student: Convertible {      var date1: NSDate?      var date2: NSDate?      var date3: Date?      var date4: Date?      var date5: Date?      var date6: Date?      var date7: Date?  }    let milliseconds: TimeInterval = 1565922866    let json: [String: Any] = [      "date1": milliseconds,      "date2": Date(timeIntervalSince1970: milliseconds),      "date3": milliseconds,      "date4": NSDate(timeIntervalSince1970: milliseconds),      "date5": "(milliseconds)",      "date6": NSDecimalNumber(string: "(milliseconds)"),      "date7": Decimal(string: "(milliseconds)") as Any  ]    let student = json.kj.model(Student.self)  XCTAssert(student.date1?.timeIntervalSince1970 == milliseconds)  XCTAssert(student.date2?.timeIntervalSince1970 == milliseconds)  XCTAssert(student.date3?.timeIntervalSince1970 == milliseconds)  XCTAssert(student.date4?.timeIntervalSince1970 == milliseconds)  XCTAssert(student.date5?.timeIntervalSince1970 == milliseconds)  XCTAssert(student.date6?.timeIntervalSince1970 == milliseconds)  XCTAssert(student.date7?.timeIntervalSince1970 == milliseconds)

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.kj.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.kj.model(Student2.self)  XCTAssert(student2?.grade1 == .bad)  XCTAssert(student2?.grade2 == .good)  XCTAssert(student2?.grade3 == .great)  XCTAssert(student2?.grade4 == .perfect)

Array

// 支持Array、NSArray、NSMutableArray与Set、NSSet、NSMutableSet之间自动转换    struct Person: Convertible {      var array1: [Int]?      var array2: NSArray?      var array3: NSMutableArray?      var array4: [Int]?      var array5: NSArray?      var array6: NSMutableArray?  }    let array = [1, 2, 3]    let json: [String: Any] = [      "array1": NSMutableArray(array: array),      "array2": array,      "array3": array,      "array4": NSMutableSet(array: array),      "array5": NSSet(array: array),      "array6": Set(array),  ]    let person = json.kj.model(Person.self)  XCTAssert(person.array1 == array)  XCTAssert(person.array2 == array as NSArray)  XCTAssert(person.array3 == NSMutableArray(array: array))    for i in array {      XCTAssert(person.array4?.contains(i) == true)      XCTAssert(person.array5?.contains(i) == true)      XCTAssert(person.array6?.contains(i) == true)  }

Set

// 支持Set、NSSet、NSMutableSet与Array、NSArray、NSMutableArray之间自动转换    struct Person: Convertible {      var set1: Set<Int>?      var set2: NSSet?      var set3: NSMutableSet?      var set4: Set<Int>?      var set5: NSSet?      var set6: NSMutableSet?  }    let array = [1, 2, 3]    let json: [String: Any] = [      "set1": NSMutableSet(array: array),      "set2": Set(array),      "set3": Set(array),      "set4": NSMutableArray(array: array),      "set5": array,      "set6": array  ]    let person = json.kj.model(Person.self)  for i in array {      XCTAssert(person.set1?.contains(i) == true)      XCTAssert(person.set2?.contains(i) == true)      XCTAssert(person.set3?.contains(i) == true)      XCTAssert(person.set4?.contains(i) == true)      XCTAssert(person.set5?.contains(i) == true)      XCTAssert(person.set6?.contains(i) == true)  }

Dictionary

// 支持Dictionary、NSDictionary、NSMutableDictionary之间自动转换    struct Person: Convertible {      var dict1: [String: Any]?      var dict2: NSDictionary?      var dict3: NSMutableDictionary?  }    let dict = ["no1": 100, "no2": 200]    let json: [String: Any] = [      "dict1": NSMutableDictionary(dictionary: dict),      "dict2": dict,      "dict3": dict  ]    let person = json.kj.model(Person.self)  for (k, v) in dict {      XCTAssert(person.dict1?[k] as? Int == v)      XCTAssert(person.dict2?[k] as? Int == v)      XCTAssert(person.dict3?[k] as? Int == v)  }