Hook Objective-C blocks with libffi. It's a powerful AOP tool for blocks. BlockHook can run your code before/instead/after invoking a block. BlockHook can even notify you when a block dealloc. You can trace the whole lifecycle of a block using BlockHook!
- Easy to use. Keep your code clear.
- Support 4 hook modes: Before, Instead, After and Dead.
- Let you modify return value and arguments.
- Support invoking original implementation.
- Reserve the whole arguments.
- Self-managed tokens.
- Support custom struct.
- Support Carthage & CocoaPods.
BlockHook needs libffi, which supports iOS and macOS.
You can run BlockHookSample iOS
or BlockHookSample macOS
target.
You can hook a block using 4 modes (before/instead/after/dead). This method returns a BHToken
instance for more control. You can remove
a BHToken
, or set custom return value to its retValue
property. Calling invokeOriginalBlock
method will invoke original implementation of the block.
- (BHToken *)block_hookWithMode:(BlockHookMode)mode
usingBlock:(id)block
BlockHook is easy to use. Its APIs take example by Aspects. Here is a full set of usage of BlockHook.
NSObject *z = NSObject.new;
int (^block)(int, int) = ^(int x, int y) {
int result = x + y;
NSLog(@"%d + %d = %d, z is a NSObject: %p", x, y, result, z);
return result;
};
BHToken *tokenInstead = [block block_hookWithMode:BlockHookModeInstead usingBlock:^(BHToken *token, int x, int y){
[token invokeOriginalBlock];
NSLog(@"let me see original result: %d", *(int *)(token.retValue));
// change the block imp and result
*(int *)(token.retValue) = x * y;
NSLog(@"hook instead: '+' -> '*'");
}];
BHToken *tokenAfter = [block block_hookWithMode:BlockHookModeAfter usingBlock:^(BHToken *token, int x, int y){
// print args and result
NSLog(@"hook after block! %d * %d = %d", x, y, *(int *)(token.retValue));
}];
BHToken *tokenBefore = [block block_hookWithMode:BlockHookModeBefore usingBlock:^(id token){
// BHToken has to be the first arg.
NSLog(@"hook before block! token:%@", token);
}];
BHToken *tokenDead = [block block_hookWithMode:BlockHookModeDead usingBlock:^(id token){
// BHToken is the only arg.
NSLog(@"block dead! token:%@", token);
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"hooked block");
int ret = block(3, 5);
NSLog(@"hooked result:%d", ret);
// remove all tokens when you don't need.
// reversed order of hook.
[tokenBefore remove];
[tokenAfter remove];
[tokenInstead remove];
NSLog(@"remove tokens, original block");
ret = block(3, 5);
NSLog(@"original result:%d", ret);
// [tokenDead remove];
});
Here is the log:
hooked block
hook before block! token:<BHToken: 0x1d00f0d80>
3 + 5 = 8, z is a NSObject: 0x1d00172b0
let me see original result: 8
hook instead: '+' -> '*'
hook after block! 3 * 5 = 15
hooked result:15
remove tokens, original block
3 + 5 = 8, z is a NSObject: 0x1d00172b0
original result:8
block dead! token:<BHToken: 0x1d00f9900>
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
To integrate BlockHook into your Xcode project using CocoaPods, specify it in your Podfile
:
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
target 'MyApp' do
pod 'BlockHook'
end
You need replace "MyApp" with your project's name.
Then, run the following command:
$ pod install
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with Homebrew using the following command:
$ brew update
$ brew install carthage
To integrate BlockHook into your Xcode project using Carthage, specify it in your Cartfile
:
github "yulingtianxia/BlockHook"
Run carthage update
to build the framework and drag the built BlockHook.framework
into your Xcode project.
After importing libffi, just add the two files BlockHook.h/m
to your project.
- If you need help or you'd like to ask a general question, open an issue.
- If you found a bug, open an issue.
- If you have a feature request, open an issue.
- If you want to contribute, submit a pull request.
yulingtianxia, [email protected]
BlockHook is available under the MIT license. See the LICENSE file for more info.
Thanks to MABlockClosure and Aspects!