在KakaJSON手冊的第2篇文章中提過:因爲JSON格式能表達的數據類型是比較有限的,因此服務器返回的JSON數據有時沒法自動轉換成客戶端想要的數據類型html
"2018-08-08 08:08:08.888"
或者"2018/08/08 08:08:08.888"
// 這2個DateFormatter僅僅爲了舉例子而寫的,具體細節根據本身需求而定 private let date1Fmt: DateFormatter = { let fmt = DateFormatter() fmt.dateFormat = "yyyy-MM-dd" return fmt }() private let date2Fmt: DateFormatter = { let fmt = DateFormatter() fmt.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS" return fmt }() struct Student: Convertible { var date1: Date? var date2: NSDate? // 實現kj_modelValue方法 // 會傳入屬性`property`以及這個屬性對應的JSON值`jsonValue` // 返回值是你但願最後設置到模型屬性上的值 // 若是返回`jsonValue`,表明不作任何事,交給KakaJSON內部處理 // 若是返回`nil`,表明忽略這個屬性,KakaJSON不會給這個屬性設值(屬性會保留它的默認值) func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? { switch property.name { // 若是jsonValue是字符串,就直接轉成Date case "date1": return (jsonValue as? String).flatMap(date1Fmt.date) // 若是jsonValue是字符串,就直接轉成Date // 因爲NSDate與Date之間是能夠橋接轉換的,因此返回Date給NSDate屬性也是沒有問題的 case "date2": return (jsonValue as? String).flatMap(date2Fmt.date) default: return jsonValue } } } let date1 = "2008-09-09" let date2 = "2011-11-12 14:20:30.888" let json: [String: Any] = [ "date1": date1, "date2": date2 ] let student = json.kj.model(Student.self) // 將Date\NSDate轉回字符串進行比較 XCTAssert(student.date1.flatMap(date1Fmt.string) == date1) XCTAssert(student.date2.flatMap(date2Fmt.string) == date2)
// 有時候服務器返回的某個字段的內容類型多是不肯定的 // 客戶端能夠先標記爲Any類型或者AnyObject類型或者協議類型等不肯定類型 struct Person: Convertible { var name: String = "" var pet: Any? func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? { // 若是不是`pet`屬性,就按照默認處理 if property.name != "pet" { return jsonValue } // 若是是`pet`屬性,而且`jsonValue`是個字典,就轉換爲`Dog`模型實例 // 具體判斷邏輯能夠根據實際開發需求而定 return (jsonValue as? [String: Any])?.kj.model(Dog.self) } } struct Dog: Convertible { var name: String = "" var weight: Double = 0.0 } let json: [String: Any] = [ "name": "Jack", "pet": ["name": "Wang", "weight": 109.5] ] let person = json.kj.model(Person.self) XCTAssert(person.name == "Jack") let pet = person.pet as? Dog XCTAssert(pet?.name == "Wang") XCTAssert(pet?.weight == 109.5) /*---------------------------------------------*/ class Book: Convertible { var name: String = "" var price: Double = 0.0 required init() {} } struct Person: Convertible { var name: String = "" // [AnyObject]、[Convertible]、NSArray、NSMutableArray var books: [Any]? func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? { if property.name != "books" { return jsonValue } // if books is `NSMutableArray`, neet convert `Array` to `NSMutableArray` // because `Array` to `NSMutableArray` is not a bridging conversion return (jsonValue as? [Any])?.kj.modelArray(Book.self) } } let name = "Jack" let books = [ (name: "Fast C++", price: 666), (name: "Data Structure And Algorithm", price: 1666) ] let json: [String: Any] = [ "name": name, "books": [ ["name": books[0].name, "price": books[0].price], ["name": books[1].name, "price": books[1].price] ] ] let person = json.kj.model(Person.self) XCTAssert(person.name == name) XCTAssert(person.books?.count == books.count) let book0 = person.books?[0] as? Book XCTAssert(book0?.name == books[0].name) XCTAssert(book0?.price == Double(books[0].price)) let book1 = person.books?[1] as? Book XCTAssert(book1?.name == books[1].name) XCTAssert(book1?.price == Double(books[1].price))
struct Student: Convertible { var age: Int = 0 var name: String = "" func kj_modelValue(from jsonValue: Any?, _ property: Property) -> Any? { switch property.name { // 若是`age`屬性的`jsonValue`是整數,就加上5 case "age": return (jsonValue as? Int).flatMap { $0 + 5 } // 若是`name `屬性的`jsonValue`是字符串,就在前面加上`kj_` case "name": return (jsonValue as? String).flatMap { "kj_" + $0 } default: return jsonValue } } } let json: [String: Any] = [ "age": 10, "name": "Jack" ] let student = json.kj.model(Student.self) XCTAssert(student.age == 15) XCTAssert(student.name == "kj_Jack")
// 關於值過濾、自定義值處理的邏輯,也能夠在模型轉換完畢以後進行 struct Student: Convertible { var age: Int = 0 var name: String = "" // 實現`kj_didConvertToModel`方法,在這裏修改轉換以後的屬性值 mutating func kj_didConvertToModel(from json: [String: Any]) { age += 5 name = "kj_" + name } } let json: [String: Any] = [ "age": 10, "name": "Jack" ] let student = json.kj.model(Student.self) XCTAssert(student.age == 15) XCTAssert(student.name == "kj_Jack")
kj_modelValue
也支持ConvertibleConfig
配置,用法相似於kj_modelKey
,參考第三篇文章