From a6d089ddc8c7d85692001fc224b9a9ba4d9fd9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=E4=BA=86=E4=B8=AAJ?= <199109106@qq.com> Date: Wed, 28 Aug 2019 23:31:20 +0800 Subject: [PATCH] keep default model value for optimization --- KakaJSON/Convert/Convertible.swift | 4 +- KakaJSON/Convert/Values.swift | 14 ++++-- .../JSON_To_Model/JTM_03_NestedModel.swift | 42 ++++++++++++++++++ README.md | 44 +++++++++++++++++++ 4 files changed, 100 insertions(+), 4 deletions(-) diff --git a/KakaJSON/Convert/Convertible.swift b/KakaJSON/Convert/Convertible.swift index 7e7caea..a1049c3 100644 --- a/KakaJSON/Convert/Convertible.swift +++ b/KakaJSON/Convert/Convertible.swift @@ -264,7 +264,9 @@ extension Convertible { } // try to convert newValue to propertyType - guard let value = Values.value(newValue, propertyType) else { + guard let value = Values.value(newValue, + propertyType, + property.get(from: model)) else { property.set(newValue, for: model) continue } diff --git a/KakaJSON/Convert/Values.swift b/KakaJSON/Convert/Values.swift index 3a594fb..b5af10b 100644 --- a/KakaJSON/Convert/Values.swift +++ b/KakaJSON/Convert/Values.swift @@ -12,7 +12,9 @@ import CoreGraphics #endif public struct Values { - static func value(_ val: Any?, _ type: Any.Type) -> Any? { + static func value(_ val: Any?, + _ type: Any.Type, + _ defaultValue: @autoclosure () -> Any? = nil) -> Any? { guard let v = val.kj_value else { return nil } if Swift.type(of: v) == type { return v } if v is NSNull { return nil } @@ -20,7 +22,7 @@ public struct Values { switch type { case is NumberValue.Type: return _number(v, type) case is StringValue.Type: return _string(v, type) - case let ct as Convertible.Type: return _model(v, ct) + case let ct as Convertible.Type: return _model(v, ct, defaultValue) case is DateValue.Type: return _date(v) case is ArrayValue.Type: return _array(v, type) case is DictionaryValue.Type: return _dictionary(v, type) @@ -73,8 +75,14 @@ private extension Values { return lower } - static func _model(_ value: Any, _ type: Convertible.Type) -> Convertible? { + static func _model(_ value: Any, + _ type: Convertible.Type, + _ defaultValue: () -> Any?) -> Convertible? { guard let json = value as? [String: Any] else { return nil } + if var model = defaultValue().kj_value as? Convertible { + model.kj_convert(from: json) + return model + } return json.kj.model(type: type) } diff --git a/KakaJSONTests/JSON_To_Model/JTM_03_NestedModel.swift b/KakaJSONTests/JSON_To_Model/JTM_03_NestedModel.swift index 69482d3..4b5708d 100644 --- a/KakaJSONTests/JSON_To_Model/JTM_03_NestedModel.swift +++ b/KakaJSONTests/JSON_To_Model/JTM_03_NestedModel.swift @@ -72,6 +72,48 @@ class JTM_03_NestedModel: XCTestCase { XCTAssert(person.dogs?["dog1"]?.name == dogs[1].name) XCTAssert(person.dogs?["dog1"]?.age == dogs[1].age) } + + func testDefaultValue() { + struct Car: Convertible { + var name: String = "" + var price: Double = 0.0 + } + + class Dog: Convertible { + var name: String = "" + var age: Int = 0 + required init() {} + init(name: String, age: Int) { + self.name = name + self.age = age + } + } + + struct Person: Convertible { + var name: String = "" + // KakaJSON will use your defaultValue instead of creating a new model + // KakaJSON will not creat a new model again if you already have a default model value + var car: Car = Car(name: "Bently", price: 106.5) + var dog: Dog = Dog(name: "Larry", age: 5) + } + + let json: [String: Any] = [ + "name": "Jake", + "car": ["price": 305.6], + "dog": ["name": "Wangwang"] + ] + + let person = json.kj.model(Person.self) + XCTAssert(person.name == "Jake") + // keep defaultValue + XCTAssert(person.car.name == "Bently") + // use value from json + XCTAssert(person.car.price == 305.6) + // use value from json + XCTAssert(person.dog.name == "Wangwang") + // keep defaultValue + XCTAssert(person.dog.age == 5) + } func testRecursive() { class Person: Convertible { diff --git a/README.md b/README.md index 303b572..e37e29d 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ Or you can login Xcode with your GitHub account. just search **KakaJSON**. - [JSONData](#jsondata) - [Nested Model 1](#nested-model-1) - [Nested Model 2](#nested-model-2) + - [Nested Model 3](#nested-model-3) - [Recursive](#recursive) - [Generic](#generic) - [Model Array](#model-array) @@ -487,6 +488,49 @@ XCTAssert(book?.name == "Fast C++") XCTAssert(book?.price == 666.6) ``` +### Nested Model3 +```swift +struct Car: Convertible { + var name: String = "" + var price: Double = 0.0 +} + +class Dog: Convertible { + var name: String = "" + var age: Int = 0 + required init() {} + init(name: String, age: Int) { + self.name = name + self.age = age + } +} + +struct Person: Convertible { + var name: String = "" + // KakaJSON will use your defaultValue instead of creating a new model + // KakaJSON will not creat a new model again if you already have a default model value + var car: Car = Car(name: "Bently", price: 106.5) + var dog: Dog = Dog(name: "Larry", age: 5) +} + +let json: [String: Any] = [ + "name": "Jake", + "car": ["price": 305.6], + "dog": ["name": "Wangwang"] +] + +let person = json.kj.model(Person.self) +XCTAssert(person.name == "Jake") +// keep defaultValue +XCTAssert(person.car.name == "Bently") +// use value from json +XCTAssert(person.car.price == 305.6) +// use value from json +XCTAssert(person.dog.name == "Wangwang") +// keep defaultValue +XCTAssert(person.dog.age == 5) +``` + ### Recursive ```swift class Person: Convertible {