@@ -105,7 +105,68 @@ print("target removed")
105
105
// CHECK-NEXT: swiftValue 42, objcValue three
106
106
// CHECK-NEXT: swiftValue 42, objcValue four
107
107
// CHECK-NEXT: swiftValue 13, objcValue four
108
+ // The next 2 logs are actually a bug and shouldn't happen
108
109
// CHECK-NEXT: swiftValue 13, objcValue four
109
110
// CHECK-NEXT: swiftValue 13, objcValue four
110
111
// CHECK-NEXT: target removed
111
112
113
+ //===----------------------------------------------------------------------===//
114
+ // Test NSKeyValueObservingCustomization issue with observing from the callbacks
115
+ //===----------------------------------------------------------------------===//
116
+
117
+ class Target2 : NSObject , NSKeyValueObservingCustomization {
118
+ dynamic var name : String ?
119
+
120
+ class Dummy : NSObject {
121
+ dynamic var name : String ?
122
+ }
123
+
124
+ // In both of the callbacks, observe another property with the same key path.
125
+ // We do it in both because we're not sure which callback is invoked first.
126
+ // This ensures that using KVO with key paths from one callback doesn't interfere
127
+ // with the ability to look up the key path using the other.
128
+ static func keyPathsAffectingValue( for key: AnyKeyPath ) -> Set < AnyKeyPath > {
129
+ print ( " keyPathsAffectingValue: key == \\ .name: " , key == \Target2 . name)
130
+ _ = Dummy ( ) . observe ( \. name) { ( _, _) in }
131
+ return [ ]
132
+ }
133
+
134
+ static func automaticallyNotifiesObservers( for key: AnyKeyPath ) -> Bool {
135
+ print ( " automaticallyNotifiesObservers: key == \\ .name: " , key == \Target2 . name)
136
+ _ = Dummy ( ) . observe ( \. name) { ( _, _) in }
137
+ return true
138
+ }
139
+ }
140
+
141
+ print ( " registering observer for Target2 " )
142
+ withExtendedLifetime ( Target2 ( ) ) { ( target) in
143
+ _ = target. observe ( \. name) { ( _, _) in }
144
+ }
145
+ print ( " observer removed " )
146
+
147
+ // CHECK-LABEL: registering observer for Target2
148
+ // CHECK-DAG: keyPathsAffectingValue: key == \.name: true
149
+ // CHECK-DAG: automaticallyNotifiesObservers: key == \.name: true
150
+ // CHECK-NEXT: observer removed
151
+
152
+ //===----------------------------------------------------------------------===//
153
+ // Test NSSortDescriptor keyPath support
154
+ //===----------------------------------------------------------------------===//
155
+
156
+ // This one doesn't really match the context of "KVO KeyPaths" but it's close enough
157
+
158
+ class Sortable1 : NSObject {
159
+ @objc var name : String ?
160
+ }
161
+
162
+ class Sortable2 : NSObject {
163
+ @objc var name : String ?
164
+ }
165
+
166
+ print ( " creating NSSortDescriptor " )
167
+ let descriptor = NSSortDescriptor ( keyPath: \Sortable1 . name, ascending: true )
168
+ _ = NSSortDescriptor ( keyPath: \Sortable2 . name, ascending: true )
169
+ print ( " keyPath == \\ Sortable1.name: " , descriptor. keyPath == \Sortable1 . name)
170
+
171
+ // CHECK-LABEL: creating NSSortDescriptor
172
+ // CHECK-NEXT: keyPath == \Sortable1.name: true
0 commit comments