设为首页 加入收藏

TOP

Runtime之方法交换
2017-10-13 10:23:49 】 浏览:1968
Tags:Runtime 方法 交换
在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有就是方法交换

方法交换的原理:在OC中调用一个方法其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用OC的动态特性,可以实现在运行时偷换selector方法的实现,达到和方法挂钩的目的。

每一个类都有一个方法列表,存放在selector的名字和方法实现的映射关系,imp有点像函数指针,指向具体的方法实现。

可以利用method_exchanggeimplementations来交换两个方法的imp

可以利用class_replaceMethod来修改类

可以利用method_setimplementation来直接设置某个方法的imp

归根结底方法交换就是偷换了selector的imp

Method Swizzling 实践

举个例子好了,就替换NSArray的objectAtIndex:方法吧,只需两个步骤。

第一步:自定义一个objectAtIndex:方法,方法名不能和系统的一样
#import <objc/runtime.h>  
#import "NSArray+Swizzle.h"
@implementation NSArray (Swizzle)  

-(id)ll_ObjectAtIndex:(NSUInteger)index{

    if (index < [self count]) {

        return [self ll_ObjectAtIndex:index];

    }else{

        return nil;

    }

}

乍一看,这不递归了么?别忘记这是我们准备调换IMP的selector,[self ll_ObjectAtIndex:index] 将会执行真的 [self objectAtIndex:index] 。 

第二步:调换IMP


+(void)load{

    Class class = NSClassFromString(@"__NSArrayI");//如果用 self、NSArray错误

    Method m1 = class_getInstanceMethod(class, @selector(objectAtIndex:));

    Method m2 = class_getInstanceMethod(class, @selector(ll_ObjectAtIndex:));

    

    method_exchangeImplementations(m1, m2);

}

定义完毕新方法后,需要弄清楚什么时候实现与系统的方法交互?
既然是给系统的方法添加额外的功能,换句话说,我们以后在开发中都是使用自己定义的方法,取代系统的方法,所以,当程序一启动,就要求能使用自己定义的功能方法.说到这里:我们必须要弄明白一下两个方法 :
 +(void)initialize(当类第一次被调用的时候就会调用该方法,整个程序运行中只会调用一次) + (void)load(当程序启动的时候就会调用该方法,换句话说,只要程序一启动就会调用load方法,整个程序运行中只会调用一次)
@end  

int main(int argc, char *argv[])
{
@autoreleasepool {
NSArray *array = @[@"0",@"1",@"2",@"3"];
NSString *string = array lastObject[6];
NSLog(@"TEST RESULT : %@",string);

return 0;
}
}
Method Swizzling 的封装
#import "NSObject+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
 


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇iPad编程 下一篇iOS 直播-闪光灯的使用

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目