@@ -26,50 +26,80 @@ public protocol SmartPublishedProtocol {
2626 static func createInstance( with value: Any ) -> Self ?
2727}
2828
29- /// PublishedContainer
30- /// @Published使属性成为一个发布者,自动发布变更。
31- /// ObservableObject可以被SwiftUI或其他观察者订阅以监听其变化。
32- @available ( iOS 13 . 0 , tvOS 13 . 0 , watchOS 6 . 0 , macOS 10 . 15 , * )
33- public class PublishedContainer < Value> : ObservableObject {
34- @Published public var wrappedValue : Value
35-
36- public init ( wrappedValue: Value ) {
37- self . wrappedValue = wrappedValue
38- }
39- }
4029
41-
42- /// 属性包装器SmartPublished,允许在声明属性时附加额外的行为。
43- /// container使用PublishedContainer管理值和发布功能。
44- /// wrappedValue提供对实际值的访问。
4530/// projectedValue提供一个发布者,可供订阅。
4631@propertyWrapper
4732@available ( iOS 13 . 0 , tvOS 13 . 0 , watchOS 6 . 0 , macOS 10 . 15 , * )
4833public struct SmartPublished < Value: Codable > : Codable {
49- private var container : PublishedContainer < Value >
5034
35+ public init ( from decoder: Decoder ) throws {
36+ let container = try decoder. singleValueContainer ( )
37+ let value = try container. decode ( Value . self)
38+ self . wrappedValue = value
39+ publisher = Publisher ( wrappedValue)
40+ }
41+
42+ public func encode( to encoder: Encoder ) throws {
43+ var container = encoder. singleValueContainer ( )
44+ try container. encode ( self . wrappedValue)
45+ }
5146 public var wrappedValue : Value {
52- get { container. wrappedValue }
53- set { container. wrappedValue = newValue }
47+ // willSet 观察器在 wrappedValue 被修改前调用,会将新的值通过 publisher 发送出去,从而通知所有的订阅者。这实现了数据更新的响应式特性。
48+ willSet {
49+ publisher. subject. send ( newValue)
50+ }
5451 }
5552
56- public var projectedValue : Published < Value > . Publisher {
57- container . $wrappedValue
53+ public var projectedValue : Publisher {
54+ publisher
5855 }
5956
60- public init ( wrappedValue: Value ) {
61- self . container = PublishedContainer ( wrappedValue: wrappedValue)
57+ private var publisher : Publisher
58+
59+ public struct Publisher : Combine . Publisher {
60+ public typealias Output = Value
61+ public typealias Failure = Never
62+
63+ // CurrentValueSubject 是 Combine 中的一种 Subject,它会保存当前值并向新订阅者发送当前值。相比于 PassthroughSubject,它在初始化时就要求有一个初始值,因此更适合这种包装属性的场景。
64+ var subject : CurrentValueSubject < Value , Never >
65+
66+ // 这个方法实现了 Publisher 协议,将 subscriber 传递给 subject,从而将订阅者连接到这个发布者上。
67+ public func receive< S> ( subscriber: S ) where S: Subscriber , Self. Failure == S . Failure , Self. Output == S . Input {
68+ subject. subscribe ( subscriber)
69+ }
70+
71+ // Publisher 的构造函数接受一个初始值,并将其传递给 CurrentValueSubject 的初始化方法。
72+ init ( _ output: Output ) {
73+ subject = . init( output)
74+ }
6275 }
6376
64- public init ( from decoder: Decoder ) throws {
65- let container = try decoder. singleValueContainer ( )
66- let value = try container. decode ( Value . self)
67- self . container = PublishedContainer ( wrappedValue: value)
77+ public init ( wrappedValue: Value ) {
78+ self . wrappedValue = wrappedValue
79+ publisher = Publisher ( wrappedValue)
6880 }
6981
70- public func encode( to encoder: Encoder ) throws {
71- var container = encoder. singleValueContainer ( )
72- try container. encode ( self . wrappedValue)
82+
83+ /// 这个下标实现了对属性包装器的自定义访问逻辑,用于在包装器内自定义 wrappedValue 的访问和修改行为。
84+ /// 参数解析:
85+ /// observed:观察者,即外部的 ObservableObject 实例。
86+ /// wrappedKeyPath:指向被包装值的引用键路径。
87+ /// storageKeyPath:指向属性包装器自身的引用键路径。
88+ public static subscript< OuterSelf: ObservableObject > (
89+ _enclosingInstance observed: OuterSelf ,
90+ wrapped wrappedKeyPath: ReferenceWritableKeyPath < OuterSelf , Value > ,
91+ storage storageKeyPath: ReferenceWritableKeyPath < OuterSelf , Self >
92+ ) -> Value {
93+ get {
94+ observed [ keyPath: storageKeyPath] . wrappedValue
95+ }
96+ set {
97+ // 在设置新值之前,如果 observed 的 objectWillChange 属性是 ObservableObjectPublisher 类型,则它会发送通知,确保在属性值更新之前,订阅者能收到通知。
98+ if let subject = observed. objectWillChange as? ObservableObjectPublisher {
99+ subject. send ( ) // 修改 wrappedValue 之前
100+ observed [ keyPath: storageKeyPath] . wrappedValue = newValue
101+ }
102+ }
73103 }
74104}
75105
0 commit comments