Skip to content

Commit d018e76

Browse files
committed
修复SmartFlat的层级问题
1 parent 3c7bc43 commit d018e76

6 files changed

Lines changed: 96 additions & 63 deletions

File tree

Example/SmartCodable/Test2ViewController.swift

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,25 @@ class Test2ViewController: BaseViewController {
1919

2020
}
2121

22+
2223
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
2324
let dict: [String: Any] = [
2425
"my_name": "Tom",
2526
"student": [
26-
"my_age": "18"
27+
"my_age": "18",
28+
"my_name": "Tom",
2729
]
2830
]
29-
let person = Person.deserialize(from: dict,options: [.key(.fromSnakeCase)])
30-
print("1111")
31+
32+
let student = StudentModel.deserialize(from: dict)
33+
print("1111 \(String(describing: student))")
3134
}
3235

33-
34-
}
35-
36-
37-
class Person11: SmartCodable {
38-
var myName: String?
39-
var student: Student?
40-
required init() {}
41-
}
42-
43-
@SmartSubclass
44-
class Student11: Person11 {
45-
var myAge: String?
36+
37+
struct FlatModel: SmartCodable {
38+
var _cover: String = "123"
39+
}
40+
struct StudentModel: SmartCodable {
41+
var student: FlatModel?
42+
}
4643
}

Example/SmartCodable/TestViewController.swift

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,39 +28,34 @@ class TestViewController: BaseViewController {
2828

2929
override func viewDidLoad() {
3030
super.viewDidLoad()
31-
let testData: [String: Any] = [
32-
"data": [
33-
"friend:apply": [
34-
"popup": 124_124_124_124,
35-
"msg_code": "123"
36-
]
37-
]
38-
]
39-
let data = NoAuthButtonResponse.deserialize(from: testData)
40-
print(data?.data["friend:apply"] as Any)
41-
}
42-
}
43-
44-
class AuthApi {
45-
46-
}
47-
struct NoAuthButtonResponse: SmartCodable {
48-
var data: [String: NoAuthButtonItem] = [:]
49-
}
50-
5131

52-
struct NoAuthButtonItem: SmartCodable {
53-
var popup: PopupType = .unsupported
54-
var msg: String = ""
32+
}
5533

56-
static func mappingForKey() -> [SmartKeyTransformer]? {
57-
return [
58-
CodingKeys.msg <--- "msg_code"
34+
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
35+
let dict: [String: Any] = [
36+
"my_name": "Tom",
37+
// "nick_name": "XiaoMing",
38+
// "student": [
39+
// "my_age": "18"
40+
// ]
5941
]
42+
43+
guard let student = StudentModel.deserialize(from: dict) else { return }
44+
print("⭐️解析结果: my_name = \(student.flatModel.my_name), nick_name = \(student.flatModel.nick_name)")
45+
}
46+
47+
48+
struct StudentModel: SmartCodable {
49+
@SmartFlat
50+
var flatModel: FlatModel = FlatModel()
51+
}
52+
53+
struct FlatModel: SmartCodable {
54+
@SmartIgnored
55+
var image: UIImage?
56+
var nick_name: String = "Mccc"
57+
var my_name: String = "default"
6058
}
61-
}
6259

63-
enum PopupType: Int, SmartCaseDefaultable {
64-
case banned = 4
65-
case unsupported = -1
6660
}
61+

Sources/SmartCodable/Core/Cache/Cachable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ extension Cachable {
4444
/// - Parameter codingPath: 当前字段或容器所在的完整解码路径。
4545
/// - Returns: 匹配路径的快照对象,若不存在则返回 `nil`。
4646
func findSnapShot(with codingPath: [CodingKey]) -> SomeSnapshot? {
47-
return snapshots.first { codingPathEquals($0.codingPath, codingPath) }
47+
return snapshots.last { codingPathEquals($0.codingPath, codingPath) }
4848
}
4949

5050
private func codingPathEquals(_ lhs: [CodingKey], _ rhs: [CodingKey]) -> Bool {

Sources/SmartCodable/Core/JSONDecoder/Decoder/DecodingCache.swift

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,32 @@ class DecodingCache: Cachable {
2121
/// - Parameter type: The Decodable type to cache
2222
func cacheSnapshot<T>(for type: T.Type, codingPath: [CodingKey]) {
2323

24-
// 减少动态派发开销,is 检查是编译时静态行为,比 as? 动态转换更高效。
25-
guard type is SmartDecodable.Type else { return }
2624

27-
if let object = type as? SmartDecodable.Type {
28-
let snapshot = DecodingSnapshot()
29-
snapshot.codingPath = codingPath
30-
// [initialValues] Lazy initialization:
31-
// Generate initial values via reflection only when first accessed,
32-
// using the recorded objectType to optimize parsing performance.
33-
snapshot.objectType = object
34-
snapshots.append(snapshot)
25+
26+
let smartType: SmartDecodable.Type?
27+
28+
/** 缓存条件
29+
* 1. 直接是 SmartDecodable
30+
* 2. 是属性包装器,且 WrappedValue 是 SmartDecodable
31+
* 3. 其它情况,不关心
32+
*/
33+
if let objectType = type as? SmartDecodable.Type {
34+
smartType = objectType
35+
} else if let wrapperType = type as? any PropertyWrapperable.Type {
36+
smartType = wrapperType.wrappedSmartDecodableType
37+
} else {
38+
return
3539
}
40+
41+
guard let object = smartType else { return }
42+
43+
let snapshot = DecodingSnapshot()
44+
snapshot.codingPath = codingPath
45+
// [initialValues] Lazy initialization:
46+
// Generate initial values via reflection only when first accessed,
47+
// using the recorded objectType to optimize parsing performance.
48+
snapshot.objectType = object
49+
snapshots.append(snapshot)
3650
}
3751

3852
/// Removes the most recent snapshot for the given type
@@ -52,11 +66,6 @@ extension DecodingCache {
5266
/// 该方法会根据传入的 `codingPath`(代表某个解码容器的位置),
5367
/// 在缓存的快照中查找对应容器,并尝试获取该容器中 `key` 对应字段的初始值。
5468
/// 如果该容器尚未初始化初始值,则会延迟初始化一次(通过反射等方式)。
55-
///
56-
/// - Parameters:
57-
/// - key: 要查找的字段对应的 `CodingKey`,若为 `nil` 则直接返回 `nil`。
58-
/// - codingPath: 当前字段所在的容器路径,用于准确定位容器上下文。
59-
/// - Returns: 若存在可用的初始值且类型匹配,则返回该值;否则返回 `nil`。
6069
func initialValueIfPresent<T>(forKey key: CodingKey?, codingPath: [CodingKey]) -> T? {
6170

6271
guard let key = key else { return nil }

Sources/SmartCodable/Core/JSONDecoder/Decoder/Impl/JSONDecoderImpl+KeyedContainer.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,11 +450,13 @@ extension JSONDecoderImpl.KeyedContainer {
450450
}
451451

452452
/// @SmartFlat的处理
453+
/// 关于SmartFlat的解析,是往前一层解析,codingPath不应该增加。
453454
if let type = type as? FlatType.Type {
454455
if type.isArray {
455456
return try? T(from: superDecoder(forKey: key))
456457
} else {
457-
return try? T(from: impl)
458+
// 这里需要走unwrap,需要cache。
459+
return try? impl.unwrap(as: T.self)
458460
}
459461
}
460462

Sources/SmartCodable/Core/PropertyWrapper/PropertyWrapperProtocol.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public protocol PropertyWrapperable {
2121

2222
init(wrappedValue: WrappedValue)
2323

24+
static var wrappedSmartDecodableType: SmartDecodable.Type? { get }
25+
2426
static func createInstance(with value: Any) -> Self?
2527

2628
/**
@@ -32,7 +34,35 @@ public protocol PropertyWrapperable {
3234
func wrappedValueDidFinishMapping() -> Self?
3335
}
3436

37+
public extension PropertyWrapperable {
38+
static var wrappedSmartDecodableType: SmartDecodable.Type? {
39+
40+
let valueType = WrappedValue.self
41+
42+
// 1️⃣ WrappedValue 本身是 SmartDecodable
43+
if let smart = valueType as? SmartDecodable.Type {
44+
return smart
45+
}
3546

47+
// 2️⃣ WrappedValue 是 Optional<SmartDecodable>
48+
if let optionalType = valueType as? _OptionalType.Type,
49+
let smart = optionalType.wrappedType as? SmartDecodable.Type {
50+
return smart
51+
}
52+
53+
return nil
54+
}
55+
}
56+
57+
protocol _OptionalType {
58+
static var wrappedType: Any.Type { get }
59+
}
60+
61+
extension Optional: _OptionalType {
62+
static var wrappedType: Any.Type {
63+
Wrapped.self
64+
}
65+
}
3666

3767
// ============================================================
3868
// 统一为所有 PropertyWrapperable 提供 Equatable / Hashable 支持

0 commit comments

Comments
 (0)