转载

runtime 方法替换 和 动态添加实例方法 结合使用

前言:方法替换,可以替换任意外部类的方法,而动态添加方法只能实现在被添加类创建的对象里,但是将方法替换和动态添加方法结合使用,可以实现,对任意外部类动态添加需要的方法,这个方法可以是类方法也可以是实例方法,这个外部类也可以是没有任何方法声明和实现的类。

主要思路:使用运行时的方法替换将在外部类将自定义方法 hy_resolveInstanceMethodhy_resolveClassMethod (用 hy_ 前缀表示是我自定义的方法)和需要被添加的类中的 resolveInstanceMethod 或者 resolveClassMethod 方法替换,替换之前在 hy_resolveInstanceMethodhy_resolveClassMethod 方法内部写好本应该在 resolveInstanceMethod 或者 resolveClassMethod 方法内部写好的runtime动态添加方法的逻辑。

有点绕,不过至少需要继续阅读源码,思考其中的逻辑,其实不难,前提是熟悉使用runtime的方法。

缺陷:1、含参数的方法难以处理,参数值需要根据实际业务逻辑而定。

Before use import <objc/message.h> ,need following:

runtime 方法替换 和 动态添加实例方法 结合使用

Create Person.h and Person.m

Person.h:

 1 #import <Foundation/Foundation.h> 2  3 @interface Person : NSObject 4  5 @end 

Person.m:

 1 #import "Person.h" 2  3 @implementation Person 4  5 @end 

Create OtherPerson.h and OtherPerson.m

OtherPerson.h:

 1 #import <Foundation/Foundation.h> 2  3 @interface OtherPerson : NSObject 4  5  6 @end 

OtherPerson.m:

  1 //  2 //  Created by HEYANG on 16/1/11.  3 //  Copyright © 2016年 HEYANG. All rights reserved.  4 //  5   6 #import "OtherPerson.h"  7 #import <objc/message.h>  8   9 @implementation OtherPerson 10  11  12 +(void)load{ 13     Class clazz = NSClassFromString(@"Person"); 14      15     //获取替换前的类方法 16     Method instance_eat =  17         class_getClassMethod(clazz, @selector(resolveInstanceMethod:)); 18     //获取替换后的类方法 19     Method instance_notEat =  20         class_getClassMethod(self, @selector(hy_resolveInstanceMethod:)); 21      22     //然后交换类方法 23     method_exchangeImplementations(instance_eat, instance_notEat); 24      25     //获取替换前的类方法 26     Method class_eat =  27         class_getClassMethod(clazz, @selector(resolveClassMethod:)); 28     //获取替换后的类方法 29     Method class_notEat =  30         class_getClassMethod(self, @selector(hy2_resolveClassMethod:)); 31      32     //然后交换类方法 33     method_exchangeImplementations(class_eat, class_notEat); 34      35 } 36  37 void eat_1(id self,SEL sel) 38 { 39     NSLog(@"到底吃不吃饭了"); 40     NSLog(@"%@ %@",self,NSStringFromSelector(sel)); 41 } 42 void eat_2(id self,SEL sel, NSString* str1,NSString* str2) 43 { 44     NSLog(@"到底吃不吃饭了"); 45     NSLog(@"%@ %@",self,NSStringFromSelector(sel)); 46     NSLog(@"打印两个参数值:%@ and %@",str1,str2); 47 } 48  49  50 +(BOOL)hy_resolveInstanceMethod:(SEL)sel{ 51     //当sel为实现方法中 有 eat 方法 52     if (sel == NSSelectorFromString(@"eat")) { 53         //就 动态添加eat方法 54          55         // 第一个参数:给哪个类添加方法 56         // 第二个参数:添加方法的方法编号 57         // 第三个参数:添加方法的函数实现(函数地址) 58         // 第四个参数:函数的类型,(返回值+参数类型) v:void @:对象->self :表示SEL->_cmd 59         class_addMethod(self, sel, (IMP)eat_1, "v@:"); 60     } 61     return YES; 62 } 63 +(BOOL)hy2_resolveClassMethod:(SEL)sel{ 64      65     if (sel == NSSelectorFromString(@"eat:with:")) { 66          67         class_addMethod(objc_getMetaClass("Person"), sel, (IMP)eat_2, "v#:@@"); 68     } 69      70     return YES; 71 } 72  73 @end 

last In file ‘main.m’:

main.m:

  1 /**  2  *  3  *  Swap Method and Dynamic add Method (交换方法和动态添加方法)  4  *  5  */  6    7 #import <Foundation/Foundation.h>  8   9 //ignore undeclared warm 忽视未声明的警告 10 #pragma clang diagnostic push 11 #pragma clang diagnostic ignored "-Wundeclared-selector" 12  13 int main(int argc, const char * argv[]) { 14     @autoreleasepool { 15         //get this Person class 拿到了这个Person类 16         Class clazz = NSClassFromString(@"Person"); 17         //get this Person Instance 拿到这个Person实例 18         id person = [[clazz alloc] init]; 19          20         //send message to 'eat' method in Person Class or Person Instance 21         //发送消息给Person类或者Person实例的‘eat’方法 不含参数 22         [person performSelector:@selector(eat) withObject:nil]; 23         //发送消息给Person类的‘eat’方法 含两个参数 24         [clazz performSelector:@selector(eat:with:)  25                         withObject:@"Hello"  26                         withObject:@"World"]; 27     } 28     return 0; 29 } 30  31 #pragma clang diagnostic pop 

the code test result

原文  http://www.cnblogs.com/goodboy-heyang/p/5126557.html
正文到此结束
Loading...