@@ -43,8 +43,134 @@ extension Reactive where Base: NSObject {
43
43
return signal
44
44
}
45
45
}
46
+
47
+ /// Create a signal which sends a `next` event, containing an array of bridged
48
+ /// arguments, at the end of every invocation of `selector` on the object.
49
+ ///
50
+ /// `trigger(for:from:)` can be used to intercept optional protocol
51
+ /// requirements by supplying the protocol as `protocol`. The instance need
52
+ /// not have a concrete implementation of the requirement.
53
+ ///
54
+ /// However, as Cocoa classes usually cache information about delegate
55
+ /// conformances, trigger signals for optional, unbacked protocol requirements
56
+ /// should be set up before the instance is assigned as the corresponding
57
+ /// delegate.
58
+ ///
59
+ /// - parameters:
60
+ /// - selector: The selector to observe.
61
+ /// - protocol: The protocol of the selector, or `nil` if the selector does
62
+ /// not belong to any protocol.
63
+ ///
64
+ /// - returns:
65
+ /// A signal that sends an array of bridged arguments.
66
+ public func signal( for selector: Selector , from protocol: Protocol ? = nil ) -> Signal < [ Any ? ] , NoError > {
67
+ return base. synchronized {
68
+ let map = associatedValue { _ in NSMutableDictionary ( ) }
69
+
70
+ let selectorName = String ( describing: selector) as NSString
71
+ if let signal = map. object ( forKey: selectorName) as! Signal < [ Any ? ] , NoError > ? {
72
+ return signal
73
+ }
74
+
75
+ let ( signal, observer) = Signal < [ Any ? ] , NoError > . pipe ( )
76
+ let isSuccessful = base. _rac_setupInvocationObservation ( for: selector,
77
+ protocol: `protocol`,
78
+ receiver: bridge ( observer) )
79
+ precondition ( isSuccessful)
80
+
81
+ lifetime. ended. observeCompleted ( observer. sendCompleted)
82
+ map. setObject ( signal, forKey: selectorName)
83
+
84
+ return signal
85
+ }
86
+ }
87
+ }
88
+
89
+ private func bridge( _ observer: Observer < [ Any ? ] , NoError > ) -> ( RACSwiftInvocationArguments ) -> Void {
90
+ return { arguments in
91
+ let count = arguments. count
92
+
93
+ var bridged = [ Any? ] ( )
94
+ bridged. reserveCapacity ( count - 2 )
95
+
96
+ // Ignore `self` and `_cmd`.
97
+ for position in 2 ..< count {
98
+ let encoding = TypeEncoding ( rawValue: arguments. argumentType ( at: position) . pointee) ?? . undefined
99
+
100
+ func extract< U> ( _ type: U . Type ) -> U {
101
+ let pointer = UnsafeMutableRawPointer . allocate ( bytes: MemoryLayout< U> . size,
102
+ alignedTo: MemoryLayout< U> . alignment)
103
+ defer {
104
+ pointer. deallocate ( bytes: MemoryLayout< U> . size,
105
+ alignedTo: MemoryLayout< U> . alignment)
106
+ }
107
+
108
+ arguments. copyArgument ( at: position, to: pointer)
109
+ return pointer. assumingMemoryBound ( to: type) . pointee
110
+ }
111
+
112
+ switch encoding {
113
+ case . char:
114
+ bridged. append ( extract ( CChar . self) )
115
+ case . int:
116
+ bridged. append ( extract ( CInt . self) )
117
+ case . short:
118
+ bridged. append ( extract ( CShort . self) )
119
+ case . long:
120
+ bridged. append ( extract ( CLong . self) )
121
+ case . longLong:
122
+ bridged. append ( extract ( CLongLong . self) )
123
+
124
+ case . unsignedChar:
125
+ bridged. append ( extract ( CUnsignedChar . self) )
126
+ case . unsignedInt:
127
+ bridged. append ( extract ( CUnsignedInt . self) )
128
+ case . unsignedShort:
129
+ bridged. append ( extract ( CUnsignedShort . self) )
130
+ case . unsignedLong:
131
+ bridged. append ( extract ( CUnsignedLong . self) )
132
+
133
+ case . bitfield:
134
+ fallthrough
135
+ case . unsignedLongLong:
136
+ bridged. append ( extract ( CUnsignedLongLong . self) )
137
+
138
+ case . float:
139
+ bridged. append ( extract ( CFloat . self) )
140
+ case . double:
141
+ bridged. append ( extract ( CDouble . self) )
142
+
143
+ case . bool:
144
+ bridged. append ( extract ( CBool . self) )
145
+ case . void:
146
+ bridged. append ( ( ) )
147
+
148
+ case . cString:
149
+ var pointer : UnsafePointer < Int8 > ?
150
+ arguments. copyArgument ( at: position, to: & pointer)
151
+ bridged. append ( pointer. map ( String . init ( cString: ) ) )
152
+
153
+ case . object:
154
+ bridged. append ( extract ( ( AnyObject? ) . self) )
155
+ case . type:
156
+ bridged. append ( extract ( ( AnyClass? ) . self) )
157
+
158
+ case . selector:
159
+ bridged. append ( arguments. selectorString ( at: position) )
160
+
161
+ case . array:
162
+ bridged. append ( extract ( OpaquePointer . self) )
163
+
164
+ case . undefined:
165
+ bridged. append ( nil )
166
+ }
167
+ }
168
+
169
+ observer. send ( value: bridged)
170
+ }
46
171
}
47
172
173
+
48
174
private enum TypeEncoding : Int8 {
49
175
// Integer
50
176
case char = 99
@@ -72,6 +198,7 @@ private enum TypeEncoding: Int8 {
72
198
case selector = 58
73
199
case array = 91
74
200
case bitfield = 98
75
- case pointer = 94
76
201
// Note: Structure `{` and union `(` are not supported.
202
+
203
+ case undefined = - 1
77
204
}
0 commit comments