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 to swizzle elegantly in Swift. It is fully written in Swift 5.2+ and works on `@objc dynamic` Swift functions or Objective-C instance methods. API documentation available at [interposekit.com](http://interposekit.com/), and some[implementation thoughts on my blog](https://steipete.com/posts/interposekit/).
11
+
InterposeKit is a modern library to swizzle elegantly in Swift. It is [well-documented](http://interposekit.com/), [tested](https://github.com/jsteipete/InterposeKit/actions?query=workflow%3ASwiftPM), written in "pure" Swift 5.2 and works on `@objc dynamic` Swift functions or Objective-C instance methods. The Inspiration for InterposeKit was [a race condition in Mac Catalyst](https://steipete.com/posts/mac-catalyst-crash-hunt/), which required tricky swizzling to fix, I also wrote up [implementation thoughts on my blog](https://steipete.com/posts/interposekit/).
12
12
13
13
Instead of [adding new methods and exchanging implementations](https://nshipster.com/method-swizzling/) based on [`method_exchangeImplementations`](https://developer.apple.com/documentation/objectivec/1418769-method_exchangeimplementations), this library replaces the implementation directly using [`class_replaceMethod`](https://developer.apple.com/documentation/objectivec/1418677-class_replacemethod). This avoids some of [the usual problems with swizzling](https://pspdfkit.com/blog/2019/swizzling-in-swift/).
14
14
15
15
You can call the original implementation and add code before, instead or after a method call.
16
16
This is similar to the [Aspects library](https://github.com/steipete/Aspects), but doesn't yet do dynamic subclassing.
17
17
18
+
Compare: [Swizzling a property without helper and with InterposeKit](https://gist.github.com/steipete/f955aaa0742021af15add0133d8482b9)
19
+
18
20
## Usage
19
21
20
22
Let's say you want to amend `sayHi` from `TestClass`:
@@ -51,7 +53,7 @@ let interposer = try Interpose(TestClass.self) {
51
53
interposer.revert()
52
54
```
53
55
54
-
Here's what we get when calling `print(TestClass().sayHi())`
56
+
Here's what we get when calling `print(TestClass().sayHi())`
Before Interposing <InterposeTests.TestClass: 0x7fa0b160c1e0>
@@ -62,7 +64,7 @@ Hi there 👋 and Interpose
62
64
63
65
## Key Facts
64
66
65
-
- Interpose directly modifies the implementaton of a `Method`, which is [better than selector-based swizzling]((https://pspdfkit.com/blog/2019/swizzling-in-swift/)).
67
+
- Interpose directly modifies the implementation of a `Method`, which is [better than selector-based swizzling]((https://pspdfkit.com/blog/2019/swizzling-in-swift/)).
66
68
- Hooks can easily be undone via calling `revert()`. This also checks and errors if someone else changed stuff in between.
67
69
- Pure Swift, no `NSInvocation`, which requires boxing and can be slow.
68
70
- No Type checking. If you have a typo or forget a `convention` part, this will crash at runtime.
Naming it Interpose was the plan, but then [SR-898](https://bugs.swift.org/browse/SR-898) came. While having a class with the same name as the module works [in most cases](https://forums.swift.org/t/frameworkname-is-not-a-member-type-of-frameworkname-errors-inside-swiftinterface/28962), [this breaks](https://twitter.com/BalestraPatrick/status/1260928023357878273) when you enable build-for-distribution. There's some [discussion](https://forums.swift.org/t/pitch-fully-qualified-name-syntax/28482/81) to get that fixed, but this will be more towards end of 2020, if even.
95
97
96
98
### I want to hook into Swift! You made another ObjC swizzle thingy, why?
97
-
UIKit and AppKit won't go away, and the bugs won't go away either. I see this as a rarely-needed instrument to fix system-level issues. There are ways to do some of that in Swift, but that's a separate (and much more difficult!) project.
99
+
UIKit and AppKit won't go away, and the bugs won't go away either. I see this as a rarely-needed instrument to fix system-level issues. There are ways to do some of that in Swift, but that's a separate (and much more difficult!) project.
98
100
99
101
### Can I ship this?
100
-
Yes, absolutely. The goal for this one prokect is a simple library that doesn't try to be too smart. I did this in [Aspects](https://github.com/steipete/Aspects) and while I loved this to no end, it's problematic and can cause side-effects with other code that tries to be clever. InterposeKit is boring, so you don't have to worry about conditions like "We added New Relic to our app and now [your thing crashes](https://github.com/steipete/Aspects/issues/21)".
102
+
Yes, absolutely. The goal for this one project is a simple library that doesn't try to be too smart. I did this in [Aspects](https://github.com/steipete/Aspects) and while I loved this to no end, it's problematic and can cause side-effects with other code that tries to be clever. InterposeKit is boring, so you don't have to worry about conditions like "We added New Relic to our app and now [your thing crashes](https://github.com/steipete/Aspects/issues/21)".
101
103
102
104
### It does not do X!
103
105
Pull Requests welcome! You might wanna open a draft before to lay out what you plan, I want to keep the feature-set minimal so it stays simple and no-magic.
@@ -122,12 +124,12 @@ Add `github "steipete/InterposeKit"` to your `Cartfile`.
122
124
## Improvement Ideas
123
125
124
126
- Write proposal to allow to [convert the calling convention of existing types](https://twitter.com/steipete/status/1266799174563041282?s=21).
125
-
- Use the C block struct to perfom type checking between Method type and C type (I do that in [Aspects library](https://github.com/steipete/Aspects)), it's still a runtime crash but could be at hook time, not when we call it.
127
+
- Use the C block struct to perform type checking between Method type and C type (I do that in [Aspects library](https://github.com/steipete/Aspects)), it's still a runtime crash but could be at hook time, not when we call it.
126
128
- Add object-based hooking with dynamic subclassing (Aspects again)
127
129
- Add [dyld_dynamic_interpose](https://twitter.com/steipete/status/1258482647933870080) to hook pure C functions
128
130
- Combine Promise-API for `Interpose.whenAvailable` for better error bubbling.
129
131
- Experiment with [Swift function hooking](https://github.com/rodionovd/SWRoute/wiki/Function-hooking-in-Swift)? ⚡️
130
-
- Test against Swift Nightly as Chron Jpb
132
+
- Test against Swift Nightly as Cron Job
131
133
- I'm sure there's more - Pull Requests or [comments](https://twitter.com/steipete) very welcome!
0 commit comments