Skip to content

Commit 85f9f5f

Browse files
committed
feat: Custom interception handlers support
1 parent 3bb27d4 commit 85f9f5f

File tree

1 file changed

+42
-15
lines changed

1 file changed

+42
-15
lines changed

Sources/Interception/NSObject+Interception.swift

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ extension NSObject {
2727
/// - action: Action to perform when `selector` was triggered
2828
public func setInterceptionHandler(
2929
for selector: Selector,
30-
key: AnyHashable = "__default",
30+
key: AnyHashable = "__default_handler__",
3131
action: ((InterceptionResult<Any, Any>) -> Void)?
3232
) {
3333
let handler = _intercept(selector)
34-
handler.register(action, for: key)
34+
handler.register(action.map(SimpleInterceptionHandler.init), for: key)
3535
}
3636

3737
/// Sets interception handler, which accepts ``InterceptionResult`` containing a tuple
@@ -56,17 +56,19 @@ extension NSObject {
5656
}
5757

5858
handler.register(
59-
{
59+
SimpleInterceptionHandler {
6060
action($0.unsafeCast(
6161
args: Args.self,
6262
output: Output.self
63-
)) },
63+
))
64+
},
6465
for: key
6566
)
6667
}
6768

6869
/// Setup the method interception.
69-
@nonobjc fileprivate func _intercept(_ selector: Selector) -> InterceptionHanlders {
70+
@_spi(Internals)
71+
@nonobjc public func _intercept(_ selector: Selector) -> InterceptionHandlers {
7072
guard let method = class_getInstanceMethod(objcClass, selector) else {
7173
fatalError(
7274
"Selector `\(selector)` does not exist in class `\(String(describing: objcClass))`."
@@ -78,7 +80,7 @@ extension NSObject {
7880

7981
return synchronized(self) {
8082
let alias = selector.alias
81-
let handlerKey = AssociationKey<InterceptionHanlders?>(alias)
83+
let handlerKey = AssociationKey<InterceptionHandlers?>(alias)
8284
let interopAlias = selector.interopAlias
8385

8486
if let handler = associations.value(forKey: handlerKey) {
@@ -138,7 +140,7 @@ extension NSObject {
138140
}
139141
}
140142

141-
let handler = InterceptionHanlders()
143+
let handler = InterceptionHandlers()
142144
associations.setValue(handler, forKey: handlerKey)
143145

144146
// Start forwarding the messages of the selector.
@@ -163,7 +165,7 @@ private func enableMessageForwarding(_ realClass: AnyClass, _ selectorCache: Sel
163165
let interopAlias = selectorCache.interopAlias(for: selector)
164166

165167
defer {
166-
let handlerKey = AssociationKey<InterceptionHanlders?>(alias)
168+
let handlerKey = AssociationKey<InterceptionHandlers?>(alias)
167169
if let handler = objectRef.takeUnretainedValue().associations.value(forKey: handlerKey) {
168170
handler(invocation)
169171
}
@@ -320,18 +322,43 @@ private func setupMethodSignatureCaching(_ realClass: AnyClass, _ signatureCache
320322
)
321323
}
322324

325+
@_spi(Internals)
326+
public protocol InterceptionHandlerProtocol {
327+
func handle(_ result: InterceptionResult<Any, Any>)
328+
}
329+
330+
extension InterceptionHandlerProtocol {
331+
@inlinable
332+
public func callAsFunction(_ result: InterceptionResult<Any, Any>) {
333+
self.handle(result)
334+
}
335+
}
336+
337+
@_spi(Internals)
338+
public struct SimpleInterceptionHandler: InterceptionHandlerProtocol {
339+
private var _action: (InterceptionResult<Any, Any>) -> Void
340+
341+
init(_ action: @escaping (InterceptionResult<Any, Any>) -> Void) {
342+
self._action = action
343+
}
344+
345+
public func handle(_ result: InterceptionResult<Any, Any>) {
346+
self._action(result)
347+
}
348+
}
349+
323350
/// The state of an intercepted method specific to an instance.
324-
private final class InterceptionHanlders {
325-
typealias Action = (InterceptionResult<Any, Any>) -> Void
326-
private var handlers: [AnyHashable: Action] = [:]
351+
@_spi(Internals)
352+
public final class InterceptionHandlers {
353+
private var storage: [AnyHashable: InterceptionHandlerProtocol] = [:]
327354

328-
func register(_ action: Action?, for key: AnyHashable) {
329-
handlers[key] = action
355+
public func register(_ action: InterceptionHandlerProtocol?, for key: AnyHashable) {
356+
storage[key] = action
330357
}
331358

332-
func callAsFunction(_ invocation: AnyObject) {
359+
public func callAsFunction(_ invocation: AnyObject) {
333360
let unpackedInvocation = unpackInvocation(invocation)
334-
handlers.values.forEach { $0(unpackedInvocation) }
361+
storage.values.forEach { $0(unpackedInvocation) }
335362
}
336363
}
337364

0 commit comments

Comments
 (0)