Skip to content

H2OB/BlockHook

 
 

Repository files navigation

BlockHook

Platform CI Status Version Carthage compatible codecov Codacy Badge GitHub release Twitter Follow

BlockHook

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!

📚 Article

🌟 Features

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

🔮 Example

BlockHook needs libffi, which supports iOS and macOS. You can run BlockHookSample iOS or BlockHookSample macOS target.

🐒 How to use

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>

📲 Installation

CocoaPods

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

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.

Manual

After importing libffi, just add the two files BlockHook.h/m to your project.

❤️ Contributed

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

👨🏻‍💻 Author

yulingtianxia, yulingtianxia@gmail.com

👮🏻 License

BlockHook is available under the MIT license. See the LICENSE file for more info.

Thanks to MABlockClosure and Aspects!

About

Hook Objective-C blocks with libffi.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C 69.4%
  • Objective-C 29.5%
  • Ruby 1.1%