You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**InterposeKit** is a modern library for hooking Objective-C methods in Swift, also known as method swizzling. It supports both class-based and object-based hooks and it provides a clean, block-based, Swift-friendly API.
5
+
**InterposeKit** is a modern library for hooking Objective-C methods in Swift, also known as method swizzling. It supports both class-based and object-based hooks, and it provides a clean, block-based, Swift-friendly API.
6
6
7
-
This is a continuation and modernization of [Peter Steinberger’s original implementation](https://github.com/steipete/InterposeKit). For the background on why and how this revamp came about, see [my blog post](#). If you’re migrating, check out [what’s changed](#).
7
+
This is a continuation and modernization of [Peter Steinberger’s original implementation](https://github.com/steipete/InterposeKit). <!--For the background on why and how this revamp came about, see [my blog post](#). -->If you’re migrating, check out [what’s changed](#what-has-changed).
8
8
9
9
## Key Features
10
10
11
11
- Swift-friendly, modern, and minimal API.
12
-
- Block-based hooks targeting both classes and individual objects.
12
+
- Block-based hooks using direct `Method` implementation replacement under the hood rather than less-safe [selector-based swizzling](https://pspdfkit.com/blog/2019/swizzling-in-swift/).
13
+
- Ability to target both classes and individual objects.
13
14
- Support for both instance and class methods.
14
-
- Hooks get access to the original implementation via a proxy.
15
15
- Object hooks are safely isolated using runtime subclassing, similar to the KVO mechanism.
16
+
- Hooks get access to the original method implementation via a proxy.
16
17
- Hooks can be applied immediately or prepared and applied later, and safely reverted at any time[^1].
17
-
- Direct `Method` implementation replacement rather than less-safe [selector-based swizzling](https://pspdfkit.com/blog/2019/swizzling-in-swift/).
18
-
- Typed signatures must be provided for both the original method and the hook block, enabling an ergonomic API.
19
-
- There’s no runtime type checking, and the signature has to be written twice—a trade-off to avoid `NSInvocation`.
20
-
- Written almost entirely in Swift on top of the Objective-C runtime[^2].
18
+
- Typed signatures must be explicitly provided for both the original method and the hook block. This adds some boilerplate but ensures a clean API and better performance compared to using `NSInvocation`[^2].
19
+
- Written almost entirely in Swift on top of the Objective-C runtime[^3].
21
20
22
21
## Requirements
23
22
24
23
- Swift 5.9 or later
25
24
- Xcode 15 or later
26
25
- Apple platforms only (macOS, iOS, tvOS, watchOS)
27
-
- arm64 or x86_64 architectures
26
+
-`arm64` or `x86_64` architectures
28
27
29
28
## Installation
30
29
@@ -36,7 +35,7 @@ If you’re adding InterposeKit using a `Package.swift` manifest, include it in
You can check out the extensive test suite to see more advanced examples or the example Xcode project to see more real-life examples of tweaking AppKit classes.
123
122
124
-
## What’s Changed
123
+
<h2id="what-has-changed">What’s Changed</h2>
125
124
126
125
Compared to the [original implementation](https://github.com/steipete/InterposeKit), this fork introduces several API and internal changes. Here is a summary of key differences with migration hints.
127
126
128
127
### Environment
129
128
130
129
- Switched the library to Swift Package Manager only. Carthage and CocoaPods support was removed.
131
130
- Raised minimum Swift version to 5.9.
132
-
- Limited to Apple platforms with arm64 and x86_64 architectures. Support for Linux was removed.
131
+
- Limited to Apple platforms with `arm64` and `x86_64` architectures. Support for Linux was removed.
133
132
134
133
### API Changes
135
134
@@ -138,25 +137,25 @@ Compared to the [original implementation](https://github.com/steipete/InterposeK
138
137
- Signature types must now be specified via parameters, improving clarity and streamlining the API.
139
138
- Renamed `hook(…)` methods to `applyHook(…)`.
140
139
- Removed fluent-style `Hook` API, meaning that methods no longer return `self`.
141
-
- Introduced `HookProxy`, which is passed into the hook builder. It still provides access to the original method implementation and selector, but hides irrelevant APIs like `revert()`.
140
+
- Introduced `HookProxy`, which is passed into the hook builder. It still provides access to the original method implementation and selector, but hides other irrelevant APIs like `revert()`.
142
141
- Hook types now use composition instead of inheritance. The public `Hook` class delegates to internal strategies conforming to `HookStrategy`.
143
142
- Object hooks now use a global counter instead of UUIDs for dynamic subclass names.
144
143
- Dynamic subclasses created at runtime are now cleaned up when the last hook is reverted on an object.
145
144
- Class hooks must now target the exact class that actually implements the method to ensure the revert functionality works correctly.
146
-
- Added initial Swift 6 support with basic concurrency checks. Should be thread-safe, but most usage is still expected to be single-threaded.
147
-
- Removed support for [delayed hooking](https://github.com/steipete/InterposeKit?tab=readme-ov-file#delayed-hooking)(`Interpose.whenAvailable(…)`) to keep the library laser-focused.
145
+
- Added initial Swift 6 support with basic concurrency checks. Should be thread-safe but most usage is still expected to be single-threaded.
146
+
- Removed support for [delayed hooking](https://github.com/steipete/InterposeKit?tab=readme-ov-file#delayed-hooking)via `Interpose.whenAvailable(…)` to keep the library laser-focused.
148
147
- …and heavily refactored the Swift part of the codebase: cleaner use of Objective-C runtime APIs, a revamped `InterposeError` enum, and new supporting types like `HookScope` or `HookState`.
149
148
150
149
### Fixes
151
150
152
-
- Fixed a crash where `IKTAddSuperImplementationToClass` was stripped in release builds per [steipete/InterposeKit#29](https://github.com/steipete/InterposeKit/issues/29) by using the fix from [steipete/InterposeKit#30](https://github.com/steipete/InterposeKit/issues/30) submitted by @Thomvis, which replaces a call via dynamic library with a direct Swift call to `IKTSuperBuilder.addSuperInstanceMethod(to:selector:)`.
153
-
- Fixed floating-point register handling on arm64 using the patch from [steipete/InterposeKit#37](https://github.com/steipete/InterposeKit/issues/37) submitted by @ishutinvv, which resolves an issue affecting swizzled methods with `CGFloat` parameters or structs like `CGPoint` and `CGRect` due to floating-point registers not being restored in the correct order after the trampoline call.
151
+
- Fixed a crash where `IKTAddSuperImplementationToClass` was stripped in release builds per [steipete/InterposeKit#29](https://github.com/steipete/InterposeKit/issues/29) by using the fix from [steipete/InterposeKit#30](https://github.com/steipete/InterposeKit/issues/30) submitted by [@Thomvis](https://github.com/Thomvis), which replaces a call via dynamic library with a direct Swift call to `IKTSuperBuilder.addSuperInstanceMethod(to:selector:)`.
152
+
- Fixed floating-point register handling on arm64 using the patch from [steipete/InterposeKit#37](https://github.com/steipete/InterposeKit/issues/37) submitted by [@ishutinvv](https://github.com/ishutinvv), which resolves an issue affecting swizzled methods with `CGFloat` parameters or structs like `CGPoint` and `CGRect` due to floating-point registers not being restored in the correct order after the trampoline call.
154
153
155
154
## Q&A
156
155
157
156
### Why did Peter call it InterposeKit?
158
157
### Why another Objective-C swizzling library?
159
-
### Can I hook pure C functions or Swift methods?
158
+
### Can I hook Swift methods? And what about pure C functions?
160
159
161
160
No. Peter had plans to experiment with [Swift method hooking](https://github.com/rodionovd/SWRoute) and hooking C functions via [`dyld_dynamic_interpose`](https://twitter.com/steipete/status/1258482647933870080), but neither made it into the library. And honestly, it doesn’t really fit the scope of this library anyway.
162
161
@@ -165,8 +164,9 @@ No. Peter had plans to experiment with [Swift method hooking](https://github.com
165
164
166
165
## Improvement Ideas
167
166
167
+
- Support for hooking KVO-enabled objects
168
168
- Signature type checking at hook construction
169
-
-Add support for reverting multiple hooks on a class in arbitrary order
169
+
-Support for reverting multiple hooks on a class in an arbitrary order
170
170
171
171
## References
172
172
@@ -183,4 +183,5 @@ No. Peter had plans to experiment with [Swift method hooking](https://github.com
183
183
This library is released under the MIT license. See [LICENSE](LICENSE) for details.
184
184
185
185
[^1]: Both applying and reverting a hook include safety checks. InterposeKit detects if the method was modified externally—such as by KVO or other swizzling—and prevents the operation if it would lead to inconsistent behavior.
186
-
[^2]: The most advanced part of this library is `ITKSuperBuilder`, a component for constructing method implementations that simply call `super`, which is [surprisingly hard to do](https://steipete.me/posts/calling-super-at-runtime/). It’s written in Objective-C and assembly, lives in its own SPM target, and is invoked from Swift. All credit goes to Peter who originally came up with this masterpiece!
186
+
[^2]: There’s currently no runtime type checking. If the specified types don’t match, it will cause a runtime crash.
187
+
[^3]: The most advanced part of this library is `ITKSuperBuilder`, a component for constructing method implementations that simply call `super`, which is [surprisingly hard to do](https://steipete.me/posts/calling-super-at-runtime/). It’s written in Objective-C and assembly, lives in its own SPM target, and is invoked from Swift. All credit goes to Peter, who originally came up with this masterpiece!
0 commit comments