Skip to content

Commit 95b574f

Browse files
committed
新增Equatable和Equatable
1 parent 1eae39a commit 95b574f

6 files changed

Lines changed: 105 additions & 169 deletions

File tree

‎Example/SmartCodable/Test2ViewController.swift‎

Lines changed: 22 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -16,78 +16,35 @@ class Test2ViewController: BaseViewController {
1616
override func viewDidLoad() {
1717
super.viewDidLoad()
1818

19-
let dict: [String: Any] = [
20-
2119

22-
"url": ["http://www.baidu.com"],
23-
24-
"float": 188.5,
25-
//
26-
"date": 1722152312,
20+
}
21+
22+
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
23+
let dict: [String: Any] = [
24+
"my_name": "Tom",
25+
"student": [
26+
"my_age": "18"
27+
]
2728
]
28-
29-
guard let model = Model.deserialize(from: dict) else { return }
30-
smartPrint(value: model)
31-
32-
guard let transDict = model.toJSONString(prettyPrint: true) else { return }
33-
print(transDict)
29+
let person = Person.deserialize(from: dict,options: [.key(.fromSnakeCase)])
30+
print("1111")
3431
}
35-
}
36-
37-
38-
extension Test2ViewController {
39-
struct Model: SmartCodable {
40-
var url: [URL]?
41-
// var float: CGFloat = 100
42-
// var date: Date? = Date()
43-
32+
33+
class Person: SmartCodable {
34+
var myName: String?
35+
var student: Student?
36+
required init() {}
37+
}
38+
class Student: SmartCodable {
39+
var myAge: String?
40+
required init() {}
4441

45-
static func mappingForValue() -> [SmartValueTransformer]? {
46-
[
47-
CodingKeys.url <--- URLTransformer(),
48-
// CodingKeys.float <--- FloatTranformer(),
49-
// CodingKeys.date <--- SmartDateTransformer(strategy: .timestamp)
42+
static func mappingForKey() -> [SmartKeyTransformer]? {
43+
return [
44+
CodingKeys.myAge <--- "my_name"
5045
]
5146
}
5247
}
5348
}
54-
struct FloatTranformer: ValueTransformable {
55-
func transformFromJSON(_ value: Any) -> Object? {
56-
return 200.0
57-
}
58-
59-
func transformToJSON(_ value: Object) -> JSON? {
60-
return nil
61-
}
62-
63-
typealias Object = CGFloat
64-
65-
typealias JSON = String
66-
}
67-
public struct URLTransformer: ValueTransformable {
6849

69-
public typealias JSON = [String]
70-
public typealias Object = [URL]
71-
private let shouldEncodeURLString: Bool
72-
private let prefix: String?
7350

74-
/**
75-
Initializes a URLTransformer with an option to encode the URL string before converting it to NSURL
76-
- parameter shouldEncodeUrlString: When true (the default value), the string is encoded before being passed
77-
- returns: an initialized transformer
78-
*/
79-
public init(prefix: String? = nil, shouldEncodeURLString: Bool = true) {
80-
self.shouldEncodeURLString = shouldEncodeURLString
81-
self.prefix = prefix
82-
}
83-
84-
85-
public func transformFromJSON(_ value: Any) -> [URL]? {
86-
let url = URL(string: "1")!
87-
return [url]
88-
}
89-
90-
public func transformToJSON(_ value: [URL]) -> [String]? {
91-
return ["1", "2", "3"]
92-
}
93-
}

‎Example/SmartCodable/TestViewController.swift‎

Lines changed: 13 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -28,118 +28,35 @@ class TestViewController: BaseViewController {
2828

2929
override func viewDidLoad() {
3030
super.viewDidLoad()
31-
3231

3332
}
3433

3534
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
3635

37-
36+
3837

3938
let dict: [String: Any] = [
40-
"name": "Mccc",
41-
"age": 20
39+
"age": 0,
40+
"name": "操作成功",
41+
4242
]
4343

44-
45-
guard let model = Model.deserialize(from: dict) else { return }
46-
44+
guard let model = SubModel.deserialize(from: dict) else { return }
4745
print(model)
48-
49-
guard let dict = model.toJSONString() else { return }
50-
print(dict)
51-
// print("\n")
52-
//
53-
//
54-
// guard let dict1 = model.toJSONString(useMappedKeys: true) else { return }
55-
// print(dict1)
5646
}
57-
58-
5947

60-
61-
struct Model: SmartCodable {
62-
// var name: String? = "Mccc"
63-
// var age: Int = 100
64-
//
65-
// @SmartDate
66-
// var date: Date? = Date()
48+
class Model: SmartCodable {
49+
var name: String = ""
6750

68-
@SmartFlat
69-
var sub: SubModel = SubModel()
70-
//
71-
//
72-
// static func mappingForKey() -> [SmartKeyTransformer]? {
73-
// [
74-
// CodingKeys.name <--- "nick_name",
75-
// CodingKeys.age <--- "self_age"
76-
// ]
77-
// }
78-
//
79-
// static func mappingForValue() -> [SmartValueTransformer]? {
80-
// [
81-
// CodingKeys.name <--- Tranformer()
82-
// ]
83-
// }
51+
required init() { }
8452
}
8553

86-
87-
struct SubModel: SmartCodable {
88-
// var hobby: String = "ball"
89-
90-
var name: String? = "Mccc"
91-
var age: Int = 100
92-
93-
// @SmartHexColor
94-
// var color: UIColor? = UIColor.red
95-
96-
97-
//
98-
// static func mappingForKey() -> [SmartKeyTransformer]? {
99-
// [
100-
//// CodingKeys.hobby <--- "ball_ball",
101-
// ]
102-
// }
103-
//
104-
// static func mappingForValue() -> [SmartValueTransformer]? {
105-
// [
106-
//// CodingKeys.hobby <--- Tranformer1(),
107-
//// CodingKeys.color <--- SmartHexColorTransformer(colorFormat: .rgb(.zeroX))
108-
// ]
109-
// }
110-
}
111-
112-
113-
struct Tranformer: ValueTransformable {
114-
func transformFromJSON(_ value: Any) -> String? {
115-
return "你好"
116-
}
117-
118-
func transformToJSON(_ value: String) -> String? {
119-
return "你好"
120-
}
121-
122-
typealias Object = String
123-
124-
typealias JSON = String
125-
126-
127-
}
128-
129-
130-
struct Tranformer1: ValueTransformable {
131-
func transformFromJSON(_ value: Any) -> String? {
132-
return "篮球"
133-
}
134-
135-
func transformToJSON(_ value: String) -> String? {
136-
return "篮球"
137-
}
138-
139-
typealias Object = String
140-
141-
typealias JSON = String
54+
@SmartSubclass
55+
class SubModel: Model {
56+
@objc var age: String = ""
14257

58+
@SmartAny
59+
var location: String = ""
14360

14461
}
14562
}

‎SmartCodable.podspec‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@
1212

1313
Pod::Spec.new do |s|
1414
s.name = 'SmartCodable'
15-
s.version = '5.1.2'
15+
s.version = '5.1.3'
1616
s.summary = 'Swift数据解析库'
1717

1818
s.homepage = 'https://github.com/iAmMccc/SmartCodable'
1919
s.license = { :type => 'MIT', :file => 'LICENSE' }
2020
s.author = { 'Mccc' => 'https://github.com/iAmMccc' }
2121
s.source = { :git => 'https://github.com/iAmMccc/SmartCodable.git', :tag => s.version.to_s }
22-
2322

2423
s.swift_version = '5.0'
2524

@@ -31,14 +30,11 @@ Pod::Spec.new do |s|
3130

3231
s.default_subspecs = ['Core']
3332

34-
3533
s.subspec 'Core' do |ss|
3634
ss.source_files = 'Sources/SmartCodable/Core/**/*{.swift}'
3735
end
3836

39-
4037
s.subspec 'Inherit' do |ss|
41-
4238
ss.ios.deployment_target = '13.0'
4339
ss.dependency 'SmartCodable/Core'
4440
ss.source_files = 'Sources/SmartCodable/MacroSupport/*{.swift}'

‎Sources/SmartCodable/Core/PropertyWrapper/PropertyWrapperProtocol.swift‎

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,65 @@ public protocol PropertyWrapperable {
3131
*/
3232
func wrappedValueDidFinishMapping() -> Self?
3333
}
34+
35+
36+
37+
// ============================================================
38+
// 统一为所有 PropertyWrapperable 提供 Equatable / Hashable 支持
39+
/// 为遵循 PropertyWrapperable 的泛型 wrapper 提供默认的 Equatable 实现
40+
extension PropertyWrapperable where WrappedValue: Equatable, Self: Equatable {
41+
public static func == (lhs: Self, rhs: Self) -> Bool {
42+
lhs.wrappedValue == rhs.wrappedValue
43+
}
44+
}
45+
46+
/// 为遵循 PropertyWrapperable 的泛型 wrapper 提供默认的 Hashable 实现
47+
extension PropertyWrapperable where WrappedValue: Hashable, Self: Hashable {
48+
public func hash(into hasher: inout Hasher) {
49+
hasher.combine(wrappedValue)
50+
}
51+
}
52+
53+
// ============================================================
54+
// 泛型 wrapper 的空声明扩展
55+
// 由于 Swift 泛型限制,编译器无法自动将泛型 wrapper 标记为 Equatable / Hashable
56+
// 所以必须显式声明遵循协议,同时条件约束 WrappedValue
57+
58+
extension SmartFlat: Equatable where T: Equatable {}
59+
extension SmartFlat: Hashable where T: Hashable {}
60+
61+
extension SmartIgnored: Equatable where T: Equatable {}
62+
extension SmartIgnored: Hashable where T: Hashable {}
63+
64+
extension SmartAny: Equatable where T: Equatable {}
65+
extension SmartAny: Hashable where T: Hashable {}
66+
67+
68+
69+
// 非泛型
70+
// 因为非泛型 wrapper 的类型固定,不依赖泛型约束,所以可以直接声明协议遵循
71+
extension SmartDate: Equatable {}
72+
extension SmartDate: Hashable {}
73+
74+
extension SmartHexColor: Equatable {
75+
public static func == (lhs: SmartHexColor, rhs: SmartHexColor) -> Bool {
76+
switch (lhs.wrappedValue?.rgbaComponents, rhs.wrappedValue?.rgbaComponents) {
77+
case let (l?, r?):
78+
return l.r == r.r && l.g == r.g && l.b == r.b && l.a == r.a
79+
case (nil, nil):
80+
return true
81+
default:
82+
return false
83+
}
84+
}
85+
}
86+
extension SmartHexColor: Hashable {
87+
public func hash(into hasher: inout Hasher) {
88+
if let components = wrappedValue?.rgbaComponents {
89+
hasher.combine(components.r)
90+
hasher.combine(components.g)
91+
hasher.combine(components.b)
92+
hasher.combine(components.a)
93+
}
94+
}
95+
}

‎Sources/SmartCodable/Core/PropertyWrapper/SmartHexColor.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ extension SmartHexColor {
295295

296296

297297

298-
private extension ColorObject {
298+
extension ColorObject {
299299
var rgbaComponents: (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat)? {
300300
#if os(macOS)
301301
guard let converted = usingColorSpace(.deviceRGB) else { return nil }

‎Sources/SmartCodableMacros/SmartSubclassMacro.swift‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,12 @@ public struct SmartSubclassMacro: MemberMacro {
9696
if !attrs.isEmpty {
9797
for attr in attrs {
9898
if let attrSyntax = attr.as(AttributeSyntax.self),
99-
let wrapperName = attrSyntax.attributeName.as(IdentifierTypeSyntax.self) {
100-
effectiveType = "\(wrapperName.name.text)<\(baseType)>"
99+
let wrapperName = attrSyntax.attributeName.as(IdentifierTypeSyntax.self)?.name.text {
100+
101+
// 如果属性使用了 @objc 修饰,则跳过它作为“属性包装器”处理
102+
if wrapperName == "objc" { continue }
103+
104+
effectiveType = "\(wrapperName)<\(baseType)>"
101105
isWrapped = true
102106
break
103107
}

0 commit comments

Comments
 (0)