MethodNotificationCenter
Objective-C Runtime Injection
MethodNotificationCenter is a lightweight framework for performing Objective-C runtime method injection for iOS, macOS, and tvOS.
Purpose
The purpose of this library is for being able to explore and understand the intricacies of the Objective-C runtime and the methods/APIs provided by Apple's libraries.
This library allows one to be notified, in a fashion very similar to Foundation's own NSNotificationCenter
, before and after a given method is called on a particular object.
It should be noted that this library is for educational purposes only. The way in which this library operates not only makes it volatile and unsuitable to production releases, but use of it would likely not pass Apple's App Store review (untested).
Installation
MethodNotificationCenter is available through CocoaPods, Carthage and the Swift Package Manager.
To install via CocoaPods, simply add the following line to your Podfile:
pod 'MethodNotificationCenter'
To install via Carthage, simply add the following line to your Cartfile:
github "SomeRandomiOSDev/MethodNotificationCenter"
To install via the Swift Package Manager add the following line to your Package.swift
file's dependencies
:
.package(url: "https://github.com/SomeRandomiOSDev/MethodNotificationCenter.git", from: "1.0.0")
Usage
First import MethodNotificationCenter at the top of your source file:
Objective-C:
@import MethodNotificationCenter;
Swift:
import MethodNotificationCenter
After importing, simply use +[MethodNotificationCenter addObserverForSelector:object:callback:]
to register a block handler for snooping in on Objective-C method calls:
Objective-C:
...
id observable = [MethodNotificationCenter addObserverForSelector:@selector(objectAtIndex:) object:array callback:^(MethodNotification *notification) {
NSLog(@"NSArray's `objectAtIndex:` method was called");
}];
Swift:
...
let observable = MethodNotificationCenter.addObserver(for: #selector(NSArray.objectAtIndex(_:)), object:nsarray) { notification in
print("NSArray's `objectAtIndex:` method was called")
}
Now your callback block will be called before and after each time the given selector is called on the object that you specified. When you are done snooping, simply pass the returned value from the registration method to +[MethodNotificationCenter removeObserver:]
Objective-C:
...
[MethodNotificationCenter removeObserver:observable];
Swift:
...
MethodNotificationCenter.removeObserver(observable)
Limitations
There are some notable limitations to the capabilities of this library:
- Method notifications aren't sent recursively. That is, you'll receive a notification for the "top-level" call of the given method, but if the method (or any of its internal method calls) calls the same method a notification will not be sent for that.
- Due to optimizations made by the Swift compiler, Swift calls to methods written in Swift (but annotated with the
@objc
attribute) are usually hard-coded by the compiler and don't use the Objective-C runtime, which prevent notifications from being sent. Classes written in Objective-C and called from Swift (or vice-versa) shouldn't have this issue. SeeTests/MethodNotificationCenterTests/MethodNotificationCenterSwiftTests/MethodNotificationCenterTests.swift
for examples.
Contributing
If you have need for a specific feature or you encounter a bug, please open an issue. If you extend the functionality of MethodNotificationCenter yourself or you feel like fixing a bug yourself, please submit a pull request.
Author
Joe Newton, [email protected]
License
MethodNotificationCenter is available under the MIT license. See the LICENSE
file for more info.