Skip to content

Commit 9060cd6

Browse files
committed
README: Various tweaks
1 parent 1fe3232 commit 9060cd6

File tree

1 file changed

+21
-20
lines changed

1 file changed

+21
-20
lines changed

README.md

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,28 @@
22

33
[![CI](https://github.com/structuredpath/InterposeKit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/structuredpath/InterposeKit/actions/workflows/ci.yml) ![Swift 5.9+](https://img.shields.io/badge/Swift-5.9%2B-orange.svg) ![Xcode 15+](https://img.shields.io/badge/Xcode-15%2B-blue.svg)
44

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.
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.
66

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).
88

99
## Key Features
1010

1111
- 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.
1314
- Support for both instance and class methods.
14-
- Hooks get access to the original implementation via a proxy.
1515
- 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.
1617
- 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].
2120

2221
## Requirements
2322

2423
- Swift 5.9 or later
2524
- Xcode 15 or later
2625
- Apple platforms only (macOS, iOS, tvOS, watchOS)
27-
- arm64 or x86_64 architectures
26+
- `arm64` or `x86_64` architectures
2827

2928
## Installation
3029

@@ -36,7 +35,7 @@ If you’re adding InterposeKit using a `Package.swift` manifest, include it in
3635

3736
```
3837
dependencies: [
39-
.package(url: "https://github.com/structuredpath/InterposeKit", from: "1.0.0")
38+
.package(url: "https://github.com/structuredpath/InterposeKit", from: "0.5.0")
4039
]
4140
```
4241

@@ -121,15 +120,15 @@ print(MyClass.getStaticValue()) // => 42
121120

122121
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.
123122

124-
## What’s Changed
123+
<h2 id="what-has-changed">What’s Changed</h2>
125124

126125
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.
127126

128127
### Environment
129128

130129
- Switched the library to Swift Package Manager only. Carthage and CocoaPods support was removed.
131130
- 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.
133132

134133
### API Changes
135134

@@ -138,25 +137,25 @@ Compared to the [original implementation](https://github.com/steipete/InterposeK
138137
- Signature types must now be specified via parameters, improving clarity and streamlining the API.
139138
- Renamed `hook(…)` methods to `applyHook(…)`.
140139
- 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()`.
142141
- Hook types now use composition instead of inheritance. The public `Hook` class delegates to internal strategies conforming to `HookStrategy`.
143142
- Object hooks now use a global counter instead of UUIDs for dynamic subclass names.
144143
- Dynamic subclasses created at runtime are now cleaned up when the last hook is reverted on an object.
145144
- 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.
148147
- …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`.
149148

150149
### Fixes
151150

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.
154153

155154
## Q&A
156155

157156
### Why did Peter call it InterposeKit?
158157
### 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?
160159

161160
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.
162161

@@ -165,8 +164,9 @@ No. Peter had plans to experiment with [Swift method hooking](https://github.com
165164

166165
## Improvement Ideas
167166

167+
- Support for hooking KVO-enabled objects
168168
- 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
170170

171171
## References
172172

@@ -183,4 +183,5 @@ No. Peter had plans to experiment with [Swift method hooking](https://github.com
183183
This library is released under the MIT license. See [LICENSE](LICENSE) for details.
184184

185185
[^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

Comments
 (0)