diff --git a/Example/Podfile.lock b/Example/Podfile.lock
index 113f0c3..e5de221 100644
--- a/Example/Podfile.lock
+++ b/Example/Podfile.lock
@@ -8,7 +8,7 @@ PODS:
- FBSnapshotTestCase/SwiftSupport (2.1.4):
- FBSnapshotTestCase/Core
- HandyJSON (5.0.0-beta.1)
- - SmartCodable (4.2.1)
+ - SmartCodable (4.2.2)
- SnapKit (5.6.0)
DEPENDENCIES:
@@ -39,7 +39,7 @@ SPEC CHECKSUMS:
CleanJSON: 910a36465ce4829e264a902ccf6d1455fdd9f980
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
HandyJSON: 582477127ab3ab65bd2e471815f1a7b846856978
- SmartCodable: ad311e84a90b09a85ba8f963ec16d30bc11fed19
+ SmartCodable: 4f52d801dbd15856fabb69110d24f31f49145734
SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25
PODFILE CHECKSUM: 7f3af03f81934df0c035518074a7abbec8fa9d3f
diff --git a/Example/Pods/Local Podspecs/SmartCodable.podspec.json b/Example/Pods/Local Podspecs/SmartCodable.podspec.json
index 360a8f7..79211bd 100644
--- a/Example/Pods/Local Podspecs/SmartCodable.podspec.json
+++ b/Example/Pods/Local Podspecs/SmartCodable.podspec.json
@@ -1,6 +1,6 @@
{
"name": "SmartCodable",
- "version": "4.2.1",
+ "version": "4.2.2",
"summary": "数据解析库",
"homepage": "https://github.com/intsig171",
"license": {
@@ -12,7 +12,7 @@
},
"source": {
"git": "https://github.com/intsig171/SmartCodable.git",
- "tag": "4.2.1"
+ "tag": "4.2.2"
},
"platforms": {
"ios": "11.0",
diff --git a/Example/Pods/Manifest.lock b/Example/Pods/Manifest.lock
index 113f0c3..e5de221 100644
--- a/Example/Pods/Manifest.lock
+++ b/Example/Pods/Manifest.lock
@@ -8,7 +8,7 @@ PODS:
- FBSnapshotTestCase/SwiftSupport (2.1.4):
- FBSnapshotTestCase/Core
- HandyJSON (5.0.0-beta.1)
- - SmartCodable (4.2.1)
+ - SmartCodable (4.2.2)
- SnapKit (5.6.0)
DEPENDENCIES:
@@ -39,7 +39,7 @@ SPEC CHECKSUMS:
CleanJSON: 910a36465ce4829e264a902ccf6d1455fdd9f980
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
HandyJSON: 582477127ab3ab65bd2e471815f1a7b846856978
- SmartCodable: ad311e84a90b09a85ba8f963ec16d30bc11fed19
+ SmartCodable: 4f52d801dbd15856fabb69110d24f31f49145734
SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25
PODFILE CHECKSUM: 7f3af03f81934df0c035518074a7abbec8fa9d3f
diff --git a/Example/Pods/Target Support Files/SmartCodable/SmartCodable-Info.plist b/Example/Pods/Target Support Files/SmartCodable/SmartCodable-Info.plist
index 03d8a17..370c557 100644
--- a/Example/Pods/Target Support Files/SmartCodable/SmartCodable-Info.plist
+++ b/Example/Pods/Target Support Files/SmartCodable/SmartCodable-Info.plist
@@ -15,7 +15,7 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 4.2.1
+ 4.2.2
CFBundleSignature
????
CFBundleVersion
diff --git a/Example/SmartCodable.xcodeproj/project.pbxproj b/Example/SmartCodable.xcodeproj/project.pbxproj
index c6009fc..c89ad5b 100644
--- a/Example/SmartCodable.xcodeproj/project.pbxproj
+++ b/Example/SmartCodable.xcodeproj/project.pbxproj
@@ -823,10 +823,12 @@
TargetAttributes = {
607FACCF1AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1;
+ DevelopmentTeam = RA2G5HURUT;
LastSwiftMigration = 0900;
};
607FACE41AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1;
+ DevelopmentTeam = RA2G5HURUT;
LastSwiftMigration = 0900;
TestTargetID = 607FACCF1AFB9204008FA782;
};
@@ -1239,6 +1241,7 @@
baseConfigurationReference = BC656B63C9031B22DEB5C8EB /* Pods-SmartCodable_Example.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEVELOPMENT_TEAM = RA2G5HURUT;
INFOPLIST_FILE = SmartCodable/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -1255,6 +1258,7 @@
baseConfigurationReference = AD8215B5E8E50F277C1C4356 /* Pods-SmartCodable_Example.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEVELOPMENT_TEAM = RA2G5HURUT;
INFOPLIST_FILE = SmartCodable/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -1270,6 +1274,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = DB7246035010143E03C7616B /* Pods-SmartCodable_Tests.debug.xcconfig */;
buildSettings = {
+ DEVELOPMENT_TEAM = RA2G5HURUT;
FRAMEWORK_SEARCH_PATHS = (
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
"$(inherited)",
@@ -1293,6 +1298,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = AFEADC35BC2373F1DC69B73B /* Pods-SmartCodable_Tests.release.xcconfig */;
buildSettings = {
+ DEVELOPMENT_TEAM = RA2G5HURUT;
FRAMEWORK_SEARCH_PATHS = (
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
"$(inherited)",
diff --git "a/Example/SmartCodable/Smart/1.Introduce(\344\275\277\347\224\250\344\273\213\347\273\215)/Introduce_12ViewController.swift" "b/Example/SmartCodable/Smart/1.Introduce(\344\275\277\347\224\250\344\273\213\347\273\215)/Introduce_12ViewController.swift"
index b87d467..3565d0b 100644
--- "a/Example/SmartCodable/Smart/1.Introduce(\344\275\277\347\224\250\344\273\213\347\273\215)/Introduce_12ViewController.swift"
+++ "b/Example/SmartCodable/Smart/1.Introduce(\344\275\277\347\224\250\344\273\213\347\273\215)/Introduce_12ViewController.swift"
@@ -13,15 +13,19 @@ import SmartCodable
class Introduce_12ViewController: BaseViewController {
var cancellables = Set()
+ var model: PublishedModel?
+
override func viewDidLoad() {
super.viewDidLoad()
let dict: [String: Any] = [
- "newName": 1,
+ "name": 1,
"age": "333333"
]
if let model = PublishedModel.deserialize(from: dict) {
+
+ self.model = model
print("反序列化后的 name 值: \(model.name)")
// 正确访问 name 属性的 Publisher
@@ -31,10 +35,14 @@ class Introduce_12ViewController: BaseViewController {
}
.store(in: &cancellables)
- // 修改 model 的 name 属性
- model.name = "Updated iOS Developer"
+
}
}
+
+ override func touchesBegan(_ touches: Set, with event: UIEvent?) {
+ // 修改 model 的 name 属性
+ model?.name = "Updated iOS Developer"
+ }
}
// 定义 PublishedModel,并实现反序列化
@@ -43,28 +51,22 @@ class PublishedModel: ObservableObject, SmartCodable {
@SmartPublished
var name: String = "iOS Developer"
-
- static func mappingForKey() -> [SmartKeyTransformer]? {
- [CodingKeys.name <--- "newName"]
- }
-
-// static func mappingForValue() -> [SmartValueTransformer]? {
-// [
-// CodingKeys.name <--- PublishedValueTransformer(),
-// ]
+//
+// static func mappingForKey() -> [SmartKeyTransformer]? {
+// [CodingKeys.name <--- "newName"]
// }
}
-struct PublishedValueTransformer: ValueTransformable {
- func transformFromJSON(_ value: Any) -> String? {
- return "good"
- }
-
- func transformToJSON(_ value: String) -> String? {
- return "gooooooood"
- }
-
- typealias Object = String
-
- typealias JSON = String
-}
+//struct PublishedValueTransformer: ValueTransformable {
+// func transformFromJSON(_ value: Any) -> String? {
+// return "good"
+// }
+//
+// func transformToJSON(_ value: String) -> String? {
+// return "gooooooood"
+// }
+//
+// typealias Object = String
+//
+// typealias JSON = String
+//}
diff --git a/Example/SmartCodable/Test2ViewController.swift b/Example/SmartCodable/Test2ViewController.swift
index 6324efa..e8fcac0 100644
--- a/Example/SmartCodable/Test2ViewController.swift
+++ b/Example/SmartCodable/Test2ViewController.swift
@@ -16,22 +16,17 @@ class Test2ViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
- let model = Model()
-
- let json = model.toDictionary()
-
- print(json)
+ let dict = [
+ "name": 1.22222
+ ]
+ let model = Model.deserialize(from: dict)
+ print(model)
}
struct Model: SmartCodable {
- var name: String = "Mccc"
-
- @IgnoredKey(supportEncode: false)
- var ignore1: String = "忽略的key1"
+ var name: String = ""
- @IgnoredKey(supportEncode: true)
- var ignore2: String = "忽略的key2"
}
}
diff --git a/Example/SmartCodable/TestViewController.swift b/Example/SmartCodable/TestViewController.swift
index d45658f..0d67a2a 100644
--- a/Example/SmartCodable/TestViewController.swift
+++ b/Example/SmartCodable/TestViewController.swift
@@ -31,13 +31,10 @@ import BTPrint
*/
-
class TestViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
-
-
}
}
diff --git a/SmartCodable.podspec b/SmartCodable.podspec
index 1027ed9..8ce0dd1 100644
--- a/SmartCodable.podspec
+++ b/SmartCodable.podspec
@@ -12,7 +12,7 @@
Pod::Spec.new do |s|
s.name = 'SmartCodable'
- s.version = '4.2.1'
+ s.version = '4.2.2'
s.summary = '数据解析库'
s.homepage = 'https://github.com/intsig171'
diff --git a/SmartCodable/Classes/SmartType/SmartPublished.swift b/SmartCodable/Classes/SmartType/SmartPublished.swift
index 1b0e30a..22a435c 100644
--- a/SmartCodable/Classes/SmartType/SmartPublished.swift
+++ b/SmartCodable/Classes/SmartType/SmartPublished.swift
@@ -26,50 +26,80 @@ public protocol SmartPublishedProtocol {
static func createInstance(with value: Any) -> Self?
}
-/// PublishedContainer
-/// @Published使属性成为一个发布者,自动发布变更。
-/// ObservableObject可以被SwiftUI或其他观察者订阅以监听其变化。
-@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
-public class PublishedContainer: ObservableObject {
- @Published public var wrappedValue: Value
-
- public init(wrappedValue: Value) {
- self.wrappedValue = wrappedValue
- }
-}
-
-/// 属性包装器SmartPublished,允许在声明属性时附加额外的行为。
-/// container使用PublishedContainer管理值和发布功能。
-/// wrappedValue提供对实际值的访问。
/// projectedValue提供一个发布者,可供订阅。
@propertyWrapper
@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
public struct SmartPublished: Codable {
- private var container: PublishedContainer
+ public init(from decoder: Decoder) throws {
+ let container = try decoder.singleValueContainer()
+ let value = try container.decode(Value.self)
+ self.wrappedValue = value
+ publisher = Publisher(wrappedValue)
+ }
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.singleValueContainer()
+ try container.encode(self.wrappedValue)
+ }
public var wrappedValue: Value {
- get { container.wrappedValue }
- set { container.wrappedValue = newValue }
+ // willSet 观察器在 wrappedValue 被修改前调用,会将新的值通过 publisher 发送出去,从而通知所有的订阅者。这实现了数据更新的响应式特性。
+ willSet {
+ publisher.subject.send(newValue)
+ }
}
- public var projectedValue: Published.Publisher {
- container.$wrappedValue
+ public var projectedValue: Publisher {
+ publisher
}
- public init(wrappedValue: Value) {
- self.container = PublishedContainer(wrappedValue: wrappedValue)
+ private var publisher: Publisher
+
+ public struct Publisher: Combine.Publisher {
+ public typealias Output = Value
+ public typealias Failure = Never
+
+ // CurrentValueSubject 是 Combine 中的一种 Subject,它会保存当前值并向新订阅者发送当前值。相比于 PassthroughSubject,它在初始化时就要求有一个初始值,因此更适合这种包装属性的场景。
+ var subject: CurrentValueSubject
+
+ // 这个方法实现了 Publisher 协议,将 subscriber 传递给 subject,从而将订阅者连接到这个发布者上。
+ public func receive(subscriber: S) where S: Subscriber, Self.Failure == S.Failure, Self.Output == S.Input {
+ subject.subscribe(subscriber)
+ }
+
+ // Publisher 的构造函数接受一个初始值,并将其传递给 CurrentValueSubject 的初始化方法。
+ init(_ output: Output) {
+ subject = .init(output)
+ }
}
- public init(from decoder: Decoder) throws {
- let container = try decoder.singleValueContainer()
- let value = try container.decode(Value.self)
- self.container = PublishedContainer(wrappedValue: value)
+ public init(wrappedValue: Value) {
+ self.wrappedValue = wrappedValue
+ publisher = Publisher(wrappedValue)
}
- public func encode(to encoder: Encoder) throws {
- var container = encoder.singleValueContainer()
- try container.encode(self.wrappedValue)
+
+ /// 这个下标实现了对属性包装器的自定义访问逻辑,用于在包装器内自定义 wrappedValue 的访问和修改行为。
+ /// 参数解析:
+ /// observed:观察者,即外部的 ObservableObject 实例。
+ /// wrappedKeyPath:指向被包装值的引用键路径。
+ /// storageKeyPath:指向属性包装器自身的引用键路径。
+ public static subscript(
+ _enclosingInstance observed: OuterSelf,
+ wrapped wrappedKeyPath: ReferenceWritableKeyPath,
+ storage storageKeyPath: ReferenceWritableKeyPath
+ ) -> Value {
+ get {
+ observed[keyPath: storageKeyPath].wrappedValue
+ }
+ set {
+ // 在设置新值之前,如果 observed 的 objectWillChange 属性是 ObservableObjectPublisher 类型,则它会发送通知,确保在属性值更新之前,订阅者能收到通知。
+ if let subject = observed.objectWillChange as? ObservableObjectPublisher {
+ subject.send() // 修改 wrappedValue 之前
+ observed[keyPath: storageKeyPath].wrappedValue = newValue
+ }
+ }
}
}