在 Runtime 改变selector所对应的 imp 来达到让原有 method 实现其他功能的目的
20130718230259187.jpg
我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP,
我们可以利用 class_replaceMethod 来修改类,
我们可以利用 method_setImplementation 来直接设置某个方法的IMP,
……
归根结底,都是偷换了selector的IMP,如下图所示
相关博客
http://blog.csdn.net/yiyaaixuexi/article/details/9374411
实战:
因为替换了 UINavigationBar 原来的按钮,导致tableView自带的滑动交互无法使用,但是可以通过interactivePopGestureRecognizer
来手动设置
- (void)viewDidLoad
{
[super viewDidLoad];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
}
但是为了防止快速滑动的过程中,多个页面响应了interactivePopGestureRecognizer
,从而发生错误,所以要在华东过程中关闭interactivePopGestureRecognizer
的响应self.interactivePopGestureRecognizer.enabled = NO
,但是overridepushViewController:animated:
不起作用,所以想在pushViewController:animated:
在runtime 中替换成包含相关额外语句的方法.
#import "UINavigationController+Swizzle.h"
#import <objc/runtime.h>
@implementation UINavigationController (Swizzle)
+ (void)load
{
//只进行一次操作,保证线程安全
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//获取原有方法
Method orig_Method = class_getInstanceMethod([UINavigationController class], @selector(pushViewController:animated:));
//获取修改后的方法
Method my_Method = class_getInstanceMethod([UINavigationController class], @selector(myPushViewController:animated:));
//交换
method_exchangeImplementations(orig_Method, my_Method);
});
}
- (void)myPushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.interactivePopGestureRecognizer.enabled = NO;
}
[self myPushViewController:viewController animated:animated];
}
@end
这样就 OK 了
下面是Github 上封装好的方法
#import "RNSwizzle.h"
#import <objc/runtime.h>
@implementation NSObject (RNSwizzle)
+ (IMP)swizzleSelector:(SEL)origSelector
withIMP:(IMP)newIMP {
Class class = [self class];
Method origMethod = class_getInstanceMethod(class,
origSelector);
IMP origIMP = method_getImplementation(origMethod);
if(!class_addMethod(self, origSelector, newIMP,
method_getTypeEncoding(origMethod)))
{
method_setImplementation(origMethod, newIMP);
}
return origIMP;
}
@end
RNSwizzle
使用
id block = ^NSString*(){
return @"********* YES it works *********";
};
IMP myIMP = imp_implementationWithBlock(block);
[NSArray swizzleSelector:@selector(lastObject) withIMP:myIMP];
NSArray *array = @[@"0", @"1", @"2", @"3"];
NSString *string = [array lastObject];
NSLog(@"Test request: %@", string);
结果:
2014-08-21 18:05:22.424 Test[22289:60b] Test request: ********* YES it works *********
网友评论