-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathKVO.swift
133 lines (109 loc) · 3.35 KB
/
KVO.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// RUN: %target-run-simple-swift | %FileCheck %s
// REQUIRES: executable_test
// REQUIRES: objc_interop
import Foundation
struct Guts {
var internalValue = 42
var value: Int {
get {
return internalValue
}
}
}
class Target : NSString {
// This dynamic property is observed by KVO
@objc dynamic var objcValue: String
// This Swift-typed property causes vtable usage on this class.
var swiftValue: Guts
override init() {
self.swiftValue = Guts()
self.objcValue = ""
super.init()
}
required init?(coder aDecoder: NSCoder) {
self.swiftValue = Guts()
self.objcValue = ""
super.init(coder: aDecoder)
}
required init(itemProviderData data: Data, typeIdentifier: String) throws {
fatalError("don't call this initializer")
}
func print() {
Swift.print("swiftValue \(self.swiftValue.value), objcValue \(objcValue)")
}
}
class Observer : NSObject {
var target: Target?
override init() { target = nil; super.init() }
func observeTarget(_ t: Target) {
target = t
target!.addObserver(self, forKeyPath:"objcValue",
options: [.new, .old],
context: nil)
}
override func observeValue(forKeyPath: String?,
of obj: Any?,
change: Dictionary<NSKeyValueChangeKey, Any>?,
context: UnsafeMutableRawPointer?) {
target!.print()
}
}
var t = Target()
var o = Observer()
print("unobserved")
// CHECK: unobserved
t.objcValue = "one"
t.objcValue = "two"
print("registering observer")
// CHECK-NEXT: registering observer
o.observeTarget(t)
print("Now witness the firepower of this fully armed and operational panopticon!")
// CHECK-NEXT: panopticon
t.objcValue = "three"
// CHECK-NEXT: swiftValue 42, objcValue three
t.objcValue = "four"
// CHECK-NEXT: swiftValue 42, objcValue four
//===----------------------------------------------------------------------===//
// Test using a proper global context reference.
//===----------------------------------------------------------------------===//
var kvoContext = Int()
class ObserverKVO : NSObject {
var target: Target?
override init() { target = nil; super.init() }
func observeTarget(_ target: Target) {
self.target = target
self.target!.addObserver(self,
forKeyPath: "objcValue",
options: [.new, .old],
context: &kvoContext)
}
func removeTarget() {
self.target!.removeObserver(self, forKeyPath:"objcValue",
context: &kvoContext)
}
override func observeValue(forKeyPath: String?,
of obj: Any?,
change: Dictionary<NSKeyValueChangeKey, Any>?,
context: UnsafeMutableRawPointer?) {
if context == &kvoContext {
target!.print()
}
}
}
var t2 = Target()
var o2 = ObserverKVO()
print("unobserved 2")
t2.objcValue = "one"
t2.objcValue = "two"
print("registering observer 2")
o2.observeTarget(t2)
print("Now witness the firepower of this fully armed and operational panopticon!")
t2.objcValue = "three"
t2.objcValue = "four"
o2.removeTarget()
print("target removed")
// CHECK: registering observer 2
// CHECK-NEXT: Now witness the firepower of this fully armed and operational panopticon!
// CHECK-NEXT: swiftValue 42, objcValue three
// CHECK-NEXT: swiftValue 42, objcValue four
// CHECK-NEXT: target removed