本文最后更新于:2021年12月22日 中午
                
              
            
            
              一、基础概念 RunTime简称运行时,就是系统在运行的时候的一些机制,其中最主要的是消息机制。
Objective-C 从三种不同的层级上与 Runtime 系统进行交互,分别是:
1、通过 Objective-C 源代码; 
2、通过 Foundation 框架的NSObject类定义的方法; 
3、通过对 runtime 函数的直接调用。二、runtime的具体实现 我们写的oc代码,它在运行的时候也是转换成了runtime方式运行的,更好的理解runtime,也能帮我们更深的掌握oc语言。每一个oc的方法,底层必然有一个与之对应的runtime方法。 
 
当我们用OC写下这样一段代码[tableView cellForRowAtIndexPath:indexPath];objectivec_msgSend(tableView, @selector(cellForRowAtIndexPath:),indexPath);
三、常见方法 1、获取属性列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @interface  People  : NSObject @property  (nonatomic , strong ) NSString  *name;@property  (nonatomic , assign ) NSUInteger  age;@end @interface  People () NSString  *aaa;@property  (nonatomic , strong ) NSString  *fatherName;@end @implementation  People  NSString  *bbb;@end 
1 2 3 4 5 6 7 8 9 void )getAllProperty {unsigned  int  count = 0 ;class ], &count);for  (unsigned  int  i=0 ; i<count; i++) {const  char  *propertyName = property_getName(propertyList[i]);NSLog (@"property---->%@" , [NSString  stringWithUTF8String:propertyName]);
打印结果: 
结论: 
1)、不管是在.h文件中定义的属性还是在.m文件中定义的属性,都可以通过获取属性列表方法来进行获取; 
2)、成员变量不同于属性,不能通过该方法来获取; 
3)、先输出的是.m文件中的属性,然后才是.h文件中的属性,并且是按照属性定义的先后顺序来保存。 
 
2、获取方法列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @interface  People  : NSObject @property  (nonatomic , strong ) NSString  *name;void )iPrintName;void )cPrintName;@end @interface  People () NSString  *aaa;@property  (nonatomic , strong ) NSString  *fatherName;@end @implementation  People  NSString  *bbb;void )cPrintName {void )printAge {@end 
1 2 3 4 5 6 7 8 9 void )getAllMethod {unsigned  int  count = 0 ;class ], &count);for  (unsigned  int  i=0 ; i<count; i++) {NSLog (@"method---->%@" , NSStringFromSelector (method_getName(method)));
结论: 
1)、类方法不能通过这个函数去获取到; 
2)、只有在.m文件中实现了的方法才能被获取到,在.h文件中定义了,但是.m中没有实现的并不能获取到; 
3)、对于使用@property定义的属性,会自动生成setter和getter方法,同样能被这个方法获取到; 
4)、.m实现中还隐藏了一个.cxx_destruct也就是oc中常见delloc方法; 
5)、保存顺序是优先保存用户在.m文件中实现的,其次是.m属性自动生成的getter和setter方法,然后是隐藏的delloc方法,最后是.h属性自动生成的getter和setter方法。 
 
3、获取成员变量列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @interface  People  : NSObject  NSString  *cccc;@property  (nonatomic , strong ) NSString  *name;@end @interface  People () NSString  *aaa;@property  (nonatomic , strong ) NSString  *fatherName;@end @implementation  People  NSString  *bbb;@end 
1 2 3 4 5 6 7 8 9 -(void)getAllIvar{int  count = 0 ;class _copyIvarList([People class ], &count ) ;for  (unsigned int  i=0 ; i<count; i++) {[i ] ;char  *ivarName = ivar_getName(myIvar ) ;NSLog(@"Ivar---->%@" , [NSString stringWithUTF8String :ivarName ]) ;
打印结果: 结论: 
4、获取协议列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @protocol  PeopleDelegate  <NSObject >void )people;@end @interface  People  : NSObject @property  (nonatomic , strong ) NSString  *name;@end @interface  People ()@property  (nonatomic , strong ) NSString  *fatherName;@end @implementation  People @end @interface  ViewController  ()<PeopleDelegate ,UITabBarDelegate ,UITableViewDataSource >@end @implementation  ViewController void )viewDidLoad {super  viewDidLoad];self  getProtocal];@end 
1 2 3 4 5 6 7 8 9 10 void )getProtocal {unsigned  int  count = 0 ;unsafe_unretained  Protocol **protocolList = class_copyProtocolList([self  class ], &count);  for  (unsigned  int  i = 0 ; i<count; i++) {const  char  *protocolName = protocol_getName(myProtocal);NSLog (@"protocol---->%@" , [NSString  stringWithUTF8String:protocolName]);
打印结果: 
结论: 
1)、只要声明遵循该协议,在引用的时候,就能获取到该类包含的协议列表,哪怕你没有指定代理的对象,也没有去实现协议的方法 
 
5、获取类方法与实例方法以及方法交换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @interface  People  : NSObject @property  (nonatomic , strong ) NSString  *name;void )printInstanceMethod;void )printClassMethod;@end @interface  People ()@property  (nonatomic , strong ) NSString  *fatherName;@end @implementation  People void )printInstanceMethod{NSLog (@"我是实例方法" );void )printClassMethod {NSLog (@"我是类方法" );@end 
示例 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -(void )getMethod {class ], @selector (printInstanceMethod));class ], @selector (printClassMethod));NSLog (@"测试前:" );NSLog (@"测试后:" );
打印结果 
6、添加方法 当项目中,需要继承某一个类(subclass),但是父类中并没有提供我需要的调用方法,而我又不清楚父类中某些方法的具体实现;或者,我需要为这个类写一个分类(category),在这个分类中,我可能需要替换/新增某个方法(注意:不推荐在分类中重写方法,而且也无法通过 super 来获取所谓父类的方法)。大致在这两种情况下,我们可以通过 class_addMethod 来实现我们想要的效果。参考 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #import "Car+MyCar.h"  #import <objectivec/runtime.h>  void  startEngine(id  self , SEL _cmd, NSString  *brand) {NSLog (@"my %@ car starts the engine" , brand);@implementation  Car  (MyCar )BOOL )resolveInstanceMethod:(SEL)sel {if  (sel == @selector (drive)) {self  class ], sel, (IMP)startEngine, "v@:@" );return  YES ;return  [super  resolveInstanceMethod:sel];
不习惯C语言代码可以替换成以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13  - (void )startEngine:(NSString  *)brand {NSLog (@"my %@ car starts the engine" , brand);BOOL )resolveInstanceMethod:(SEL)sel {if  (sel == @selector (drive)) {self  class ], sel, class_getMethodImplementation(self , @selector (startEngine:)), "v@:@" );return  YES ;return  [super  resolveInstanceMethod:sel];@end 
调用:
1 2 3 4 5 -(void )addMethod {@selector (drive) withObject:@"BMW" ];
解释:Message Forwarding  。
1 2 + (BOOL )resolveInstanceMethod:(SEL)sel;BOOL )resolveClassMethod:(SEL)sel;
这个函数在 runtime 环境下,如果没有找到该方法的实现的话就会执行。第一行判断的是传入的 SEL 名称是否匹配,接着调用 class_addMethod 方法,传入相应的参数。其中第三个参数传入的是我们添加的 C 语言函数的实现,也就是说,第三个参数的名称要和添加的具体函数名称一致。第四个参数指的是函数的返回值以及参数内容。
结果:
四、其他 一开始我以为class_addMethod和class_replaceMethod就等同于method_exchangeImplementations,但是看了下面的代码才发现,其实这俩的适用条件是不一样的,当方法没有实现的时候才能使用class_addMethod和class_replaceMethod套装,但是当方法已存在的时候,就需要使用method_exchangeImplementations,这点从if (didAddMethod)这个判定就可见一斑。 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 +(void )load{NSString  *className = NSStringFromClass (self .class);NSLog (@"classname %@" , className);static  dispatch_once_t  onceToken;dispatch_once (&onceToken, ^{class  = object_getClass((id )self );@selector (systemMethod_PrintLog);@selector (ll_imageName);class , originalSelector);class , swizzledSelector);BOOL  didAddMethod =class ,if  (didAddMethod) {class ,else  {
Demo 
资料 runtime详解 runtime奇技淫巧系列 OC最实用的runtime总结,面试、工作你看我就足够了! 
五、联系方式 邮箱:  xiebangyao_1994@163.com 相关账号: