前言 
上篇主要讲Runtime的一些术语描述和定义,Runtime的主要应用是用于消息的传递,今天会结合一些实战例子来讲下OC的消息传递机制。
普通消息传递 
在OC里,对象调用方法叫作发送消息,对象调用方法在Runtime里被转化为objc_msgSend函数来实现
1 
2 
3 
[ receiver  oneMethod ]; 
//transfer to : 
objc_msgSend ( receiver ,  @selector ( oneMethod )); 
Runtime会根据类型自动转换为下列某个函数: 
objc_msgSend :普通的消息都会通过该函数发送;  objc_msgSend_stret :消息中有数据结构作为返回值(不是简单值)时,通过此函数发送和接收返回值;  objc_msgSendSuper :和objc_msgSend类似,这里把消息发送给父类的实例;  objc_msgSendSuper_stret :和objc_msgSend_stret类似,这里把消息发送给父类的实例并接收返回值;
objc_msgSend的调用过程 
1. 先检查这个selector是否存在,不存在则忽略;   2. 接着检查selector的target是否为nil,向nil对象发送任何消息都会被忽略掉;  3. 前面两步没问题,则先在isa指针指向的class的cache里面找有没有方法调用记录,如果有,则运行对应的函数,如果没有则在class的methodLists查找方法,没有则通过super_class指针找到父类的类对象结构体,然后从methodLists查找方法,如果仍找不到,则继续通过
super_class向上一级父类结构体中查找,直到根类(NSObject);  4. 如果还是找不到,则进入消息动态解析 ;
消息动态解析 
动态解析流程图:
具体解析:  1. 通过resolveInstanceMethod,该方法决定是否动态添加方法。如果返回YES,则通过class_addMethod动态添加方法,消息得到处理,结束;如果返回NO,则进入下一步;   2. 这一步会步入forwardingTargetForSelector方法,用于指定备选对象响应这个selector,不能指定为self,如果放回某个对象则会调用对象的方法,结束。如果放回nil,则进入第三步;  3. 这一步,我们通过methodSignatureForSelector进行方法签名,如果返回nil,则消息无法处理。如果返回methodSignature则进入下一步;  4. 这步调用forwardInvocation方法,我们通过anInvocation对象做很多处理,比如修改实现方法,修改响应对象,如果方法方法调用成功,则结束。如果失败,则进入doesNotRecognizeSelector,如果没有实现这个方法会crash
实战 
通过runtime动态创建类和对象 
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 
37 
38 
39 
40 
41 
42 
43 
44 
#import <Foundation/Foundation.h> 
#import <objc/runtime.h> 
#import <objc/message.h> 
void  sayFunction ( id  self ,  SEL  _cmd ,  id  some ){ 
     NSLog ( @"%@岁的%@说:%@" , object_getIvar ( self ,  class_getInstanceVariable ([ self  class ],  "_age" )), object_getIvar ( self ,  class_getInstanceVariable ([ self  class ],  "_name" )), some ); 
 } 
 int  main ( int  argc ,  const  char  *  argv [])  { 
    @autoreleasepool  { 
         //动态创建类 
         Class  MyPeople  =  objc_allocateClassPair ([ NSObject  class ],  "Person" ,  0 ); 
 
         //为类添加成员变量 
         class_addIvar ( MyPeople ,  "_name" ,  sizeof ( NSString * ),  log2 ( sizeof ( NSString * )),  @encode ( NSString * )); 
         class_addIvar ( MyPeople ,  "_age" ,  sizeof ( int ), sizeof ( int ), @encode ( int )); 
 
         //注册方法("v@:@"代表返回值+参数列表) 
         SEL  say  =  sel_registerName ( "say:" ); 
         class_addMethod ( MyPeople ,  say ,  ( IMP ) sayFunction ,  "v@:@" ); 
 
         //注册类 
         objc_registerClassPair ( MyPeople ); 
 
         //创建实例对象 
         id  peopleInstance  =  [[ MyPeople  alloc ] init ]; 
 
         [ peopleInstance  setValue : @"李明"  forKey : @"name" ]; 
 
         //获取成员变量 
         Ivar  age  =  class_getInstanceVariable ( MyPeople ,  "_age" ); 
         object_setIvar ( peopleInstance ,  age ,  @18 ); 
 
         //发送消息 
         objc_msgSend ( peopleInstance , say , @"你好呀" ); 
 
         //销毁实例对象 
         peopleInstance  =  nil ; 
 
         //当类或子类的实例存在,则不能销毁类 
         objc_disposeClassPair ( MyPeople ); 
     } 
     return  0 ; 
 } 
tip: 
默认会出现以下错误:  
通过runtime获取类的相关信息(属性、实例变量、方法) 
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 
#import <Foundation/Foundation.h> 
 @interface  People  : NSObject { 
     NSString *  _nationality ; 
 
 } 
 @property ( nonatomic , copy ) NSString *  name ; 
@property ( nonatomic , strong ) NSNumber *  age ; 
 /** 
 * 获取所有属性 
 **/ 
-( NSDictionary * ) getAllProperties ; 
 /** 
 * 获取所有实例变量 
 **/ 
-( NSDictionary * ) getAllIvars ; 
 
 /** 
 * 获取所有方法 
 **/ 
-( NSDictionary * ) getAllMethods ; 
 @end 
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 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
#import "People.h" 
#import <objc/runtime.h> 
#import <objc/message.h> 
 @implementation  People 
 
 -( NSDictionary  * ) getAllProperties { 
    unsigned  int  count  =  0 ; 
     NSMutableDictionary *  result  =  [ @{}  mutableCopy ]; 
     objc_property_t *  properties  =  class_copyPropertyList ([ self  class ],  & count ); 
     for  ( NSUInteger  i  =  0 ;  i < count ;  i ++ )  { 
         const  char *  propertyName  =  property_getName ( properties [ i ]); 
         NSString *  name  =  [ NSString  stringWithUTF8String : propertyName ]; 
         id  propertyValue  =  [ self  valueForKey : name ]; 
         if  ( propertyValue )  { 
             result [ name ]  =  propertyValue ; 
         } else { 
             result [ name ]  =  @"value 不能为 nil" ; 
         } 
 
 
     } 
     free ( properties ); 
 
     return  result ; 
 } 
 -( NSDictionary  * ) getAllIvars { 
    unsigned  int  count  =  0 ; 
     NSMutableDictionary *  result  =  [ @{}  mutableCopy ]; 
     Ivar *  ivars  =  class_copyIvarList ([ self  class ],  & count ); 
     for  ( NSUInteger  i  =  0 ;  i < count ;  i ++ )  { 
         const  char *  ivarName  =  ivar_getName ( ivars [ i ]); 
         NSString *  name  =  [ NSString  stringWithUTF8String : ivarName ]; 
         id  value  =  [ self  valueForKey : name ]; 
         if  ( value )  { 
             result [ name ]  =  value ; 
         } else { 
             result [ name ]  =  @"value 不能为 nil" ; 
         } 
     } 
     free ( ivars ); 
     return   result ; 
 } 
 -( NSDictionary * ) getAllMethods { 
    unsigned  int  count  =  0 ; 
     NSMutableDictionary *  result  =  [ @{}  mutableCopy ]; 
     Method *  methods  =  class_copyMethodList ([ self  class ],  & count ); 
     for  ( NSUInteger  i  =  0 ;  i < count ;  i ++ )  { 
         const  char *  methodName  =  sel_getName ( method_getName ( methods [ i ])); 
         NSString *  name  =  [ NSString  stringWithUTF8String : methodName ]; 
         //获取参数列表 
         int  args  =  method_getNumberOfArguments ( methods [ i ]); 
         result [ name ]  =  [ NSString  stringWithFormat : @"args count is %d" , args - 2  ]; 
     } 
     free ( methods ); 
     return  result ; 
 } 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
#import <Foundation/Foundation.h> 
#import "People.h" 
int  main ( int  argc ,  const  char  *  argv [])  { 
    @autoreleasepool  { 
         People *  p  =  [[ People  alloc ] init ]; 
         p . name  =  @"罗大锤" ; 
         p . age  =  @( 30 ) ; 
         [ p  setValue : @"中国"  forKey : @"nationality" ]; 
         NSDictionary *  properties  =  [ p  getAllProperties ]; 
         NSDictionary *  ivars  =  [ p  getAllIvars ]; 
         NSDictionary *  methods  =  [ p  getAllMethods ]; 
         NSLog ( @"属性为:%@" , properties ); 
         NSLog ( @"实例变量:%@" , ivars ); 
         NSLog ( @"方法:%@" , methods ); 
     } 
     return  0 ; 
 } 
打印结果: 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
2016 - 05 - 13  11 : 22 : 36.298  runtime  之  获取类的相关信息 ( 属性、实例变量、方法 )[ 2783 : 307932 ]  属性为: { 
    age  =  30 ; 
     name  =  "\U7f57\U5927\U9524" ; 
 } 
2016 - 05 - 13  11 : 22 : 36.299  runtime  之  获取类的相关信息 ( 属性、实例变量、方法 )[ 2783 : 307932 ]  实例变量: { 
    "_age"  =  30 ; 
     "_name"  =  "\U7f57\U5927\U9524" ; 
     "_nationality"  =  "\U4e2d\U56fd" ; 
 } 
2016 - 05 - 13  11 : 22 : 36.299  runtime  之  获取类的相关信息 ( 属性、实例变量、方法 )[ 2783 : 307932 ]  方法: { 
    ".cxx_destruct"  =  "args count is 0" ; 
     age  =  "args count is 0" ; 
     getAllIvars  =  "args count is 0" ; 
     getAllMethods  =  "args count is 0" ; 
     getAllProperties  =  "args count is 0" ; 
     name  =  "args count is 0" ; 
     "setAge:"  =  "args count is 1" ; 
     "setName:"  =  "args count is 1" ; 
 } 
Program  ended  with  exit  code :  0 
通过Runtime给category添加属性 
1 
2 
3 
4 
5 
6 
7 
8 
9 
#import "People.h" 
 typedef  void ( ^ CallBackSomething )(); 
 @interface  People  (testCategory) 
 @property ( nonatomic , copy ) NSString *  address ; 
@property ( nonatomic , copy ) CallBackSomething  block ; 
@end 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
#import "People+testCategory.h" 
#import <objc/runtime.h> 
#import <objc/message.h> 
 
 @implementation  People  (testCategory) 
 -( void ) setAddress: ( NSString  * ) address { 
    objc_setAssociatedObject ( self ,  @selector ( address ),  address ,  OBJC_ASSOCIATION_COPY_NONATOMIC ); 
 } 
 -( NSString  * ) address { 
    return  objc_getAssociatedObject ( self ,  @selector ( address )); 
 } 
 -( void ) setBlock: ( CallBackSomething ) block { 
    objc_setAssociatedObject ( self ,  @selector ( block ),  block ,  OBJC_ASSOCIATION_COPY_NONATOMIC ); 
 } 
 -( CallBackSomething ) block { 
    return  objc_getAssociatedObject ( self ,  @selector ( block )); 
 } 
 @end 
利用Runtime给对象归档和解档 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
#import <Foundation/Foundation.h> 
 @interface  People  : NSObject < NSCoding > { 
     NSString *  _nationality ; 
 
 } 
 @property ( nonatomic , copy ) NSString *  name ; 
@property ( nonatomic , strong ) NSNumber *  age ; 
@end 
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 
37 
38 
#import "People.h" 
#import <objc/runtime.h> 
#import <objc/message.h> 
 @implementation  People 
 //归档 
-( void ) encodeWithCoder: ( NSCoder  * ) aCoder { 
    unsigned  int  count  =  0 ; 
     Ivar *  ivars  =  class_copyIvarList ([ self  class ], & count ); 
     for  ( NSUInteger  i  =  0 ;  i < count ;  i ++ )  { 
         Ivar  ivar  =  ivars [ i ]; 
         const  char *  name  =  ivar_getName ( ivar ); 
         NSString *  key  =  [ NSString  stringWithUTF8String : name ]; 
         id  value  =  [ self  valueForKey : key ]; 
         [ aCoder  encodeObject : value  forKey : key ]; 
     } 
     free ( ivars ); 
 } 
 //解档 
-( instancetype ) initWithCoder: ( NSCoder  * ) aDecoder { 
    if  ( self  =  [ super  init ])  { 
         unsigned  int  count  =  0 ; 
         Ivar *  ivars  =  class_copyIvarList ([ self  class ], & count ); 
         for  ( NSUInteger  i  =  0 ;  i < count ;  i ++ )  { 
             Ivar  ivar  =  ivars [ i ]; 
             const  char *  name  =  ivar_getName ( ivar ); 
             NSString *  key  =  [ NSString  stringWithUTF8String : name ]; 
             id  value  =  [ aDecoder  decodeObjectForKey : key ]; 
             [ self  setValue : value  forKey : key ]; 
         } 
         free ( ivars ); 
     } 
     return  self ; 
 } 
 @end 
利用Runtime实现Model与字典互转 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
#import <Foundation/Foundation.h> 
 @interface  People  : NSObject 
 @property ( nonatomic , copy ) NSString *  name ; 
@property ( nonatomic , strong ) NSNumber *  age ; 
 
 /** 
 * 字典 转 Model 
 **/ 
-( instancetype ) initWithDictionary: ( NSDictionary * )  dict ; 
 /** 
 * Model转换成字典 
 **/ 
-( NSDictionary * ) covertToDictionary ; 
@end 
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 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
#import "People.h" 
#import <objc/runtime.h> 
#import <objc/message.h> 
 @implementation  People 
 
 
 
 -( instancetype ) initWithDictionary: ( NSDictionary  * ) dict { 
    if  ( self  =  [ super  init ])  { 
         for  ( NSString *  key  in  dict )  { 
             id  val  =  dict [ key ]; 
             SEL  setter  =  [ self  propertySetterByKey : key ]; 
             if  ( setter )  { 
                 objc_msgSend ( self ,  setter , val ); 
             } 
         } 
     } 
     return  self ; 
 } 
 -( NSDictionary  * ) covertToDictionary { 
    unsigned  int  count  =  0 ; 
     objc_property_t *  properties  =  class_copyPropertyList ([ self  class ],  & count ); 
 
     if  ( count != 0 )  { 
         NSMutableDictionary *  result  =  [ @{}  mutableCopy ]; 
         for  ( NSUInteger  i  =  0 ;  i < count ;  i ++ )  { 
             const  char  *  propertyName  =  property_getName ( properties [ i ]); 
             NSString *  name  =  [ NSString  stringWithUTF8String : propertyName ]; 
 
             SEL  getter  =  [ self  propertyGetterByKey : name ]; 
             if  ( getter )  { 
                 id  value  =  objc_msgSend ( self ,  getter ); 
                 if  ( value )  { 
                     result [ name ]  =  value ; 
                 } else { 
                     result [ name ]  =  @"value 为 nil" ; 
                 } 
             } 
         } 
         free ( properties ); 
         return  result ; 
     } 
     free ( properties ); 
     return  nil ; 
 } 
 #pragma mark - 生成setter 
-( SEL ) propertySetterByKey: ( NSString * ) key { 
    //key的首字母大写 
     NSString *  propertySetterName  =  [ NSString  stringWithFormat : @"set%@:" , key . capitalizedString ]; 
     SEL  setter  =  NSSelectorFromString ( propertySetterName ); 
     if  ([ self  respondsToSelector : setter ])  { 
         return  setter ; 
     } 
     return  nil ; 
 } 
 -( SEL ) propertyGetterByKey: ( NSString * ) key { 
    SEL  getter  =  NSSelectorFromString ( key ); 
     if  ([ self  respondsToSelector : getter ])  { 
         return  getter ; 
     } 
     return  nil ; 
 } 
 @end 
消息动态解析(一) 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
#import <Foundation/Foundation.h> 
 @interface  People  : NSObject 
 @property ( nonatomic , copy ) NSString *  name ; 
 /** m文件不实现方法,通过runtime动态添加方法 
 *  通过resolveInstanceMethod:方法决定是否动态添加方法。 
    如果返回Yes则通过class_addMethod动态添加方法,消息得到处理,结束;如果返回No 
 **/ 
-( void ) sing ; 
 @end 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
#import "People.h" 
#import <objc/runtime.h> 
#import <objc/message.h> 
 
 @implementation  People 
 +( BOOL ) resolveInstanceMethod: ( SEL ) sel { 
    if  ([ NSStringFromSelector ( sel )  isEqualToString : @"sing" ])  { 
         class_addMethod ([ self  class ],  sel ,  ( IMP ) otherIMP ,  "V@:" ); 
         return  YES ; 
     } 
     return  [ super  resolveInstanceMethod : sel ]; 
 } 
 void  otherIMP ( id  self  , SEL  cmd ){ 
    NSLog ( @"%@正在唱歌" ,(( People * ) self ). name ); 
 } 
 @end 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
#import <Foundation/Foundation.h> 
#import "People.h" 
int  main ( int  argc ,  const  char  *  argv [])  { 
    @autoreleasepool  { 
         People *  p  =  [[ People  alloc ] init ]; 
         p . name  =  @"张全蛋" ; 
         [ p  sing ]; 
     } 
     return  0 ; 
 } 
打印结果: 
1 
2 
2016 - 05 - 13  11 : 24 : 16.905  runtime  之  消息动态解析 ( 一 )[ 2819 : 311517 ]  张全蛋正在唱歌 
Program  ended  with  exit  code :  0 
消息动态解析(二) 
修改Bird唱歌方法的调用对象
1 
2 
3 
4 
5 
6 
#import <Foundation/Foundation.h> 
 @interface  Bird  : NSObject 
@property ( nonatomic , copy ) NSString *  name ; 
-( void ) sing ; 
@end 
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 
#import "Bird.h" 
#import "People.h" 
@implementation  Bird 
 
 //第一步,不动态添加方法 
+( BOOL ) resolveInstanceMethod: ( SEL ) sel { 
    return  NO ; 
 } 
 //第二步,不指定备选对象响应sselector 
-( id ) forwardingTargetForSelector: ( SEL ) aSelector { 
     return  nil ; 
 } 
 //第三步,返回方法签名 
-( NSMethodSignature  * ) methodSignatureForSelector: ( SEL ) aSelector { 
    if  ([ NSStringFromSelector ( aSelector )  isEqualToString : @"sing" ])  { 
         return  [ NSMethodSignature  signatureWithObjCTypes : "v@:" ]; 
     } 
     return  [ super  methodSignatureForSelector : aSelector ]; 
 } 
 //第四部,修改调用对象 
-( void ) forwardInvocation: ( NSInvocation  * ) anInvocation { 
    People *  p  =  [[ People  alloc ] init ]; 
     p . name  =  @"张铁柱" ; 
     [ anInvocation  invokeWithTarget : p ]; 
 } 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
#import <Foundation/Foundation.h> 
#import "Bird.h" 
#import <objc/runtime.h> 
#import <objc/message.h> 
int  main ( int  argc ,  const  char  *  argv [])  { 
    @autoreleasepool  { 
         Bird *  b  =  [[ Bird  alloc ] init ]; 
         b . name  =  @"小鸟" ; 
         [ b  sing ]; 
     } 
     return  0 ; 
 } 
打印结果: 
1 
2 
2016 - 05 - 13  11 : 29 : 58.335  runtime  之  消息动态解析 ( 二 )[ 2963 : 322829 ]  张铁柱正在唱歌 
Program  ended  with  exit  code :  0 
消息动态解析(三) 
修改Person唱歌方法的实现
1 
2 
3 
4 
5 
#import <Foundation/Foundation.h> 
 @interface  People  : NSObject 
-( void ) sing ; 
@end 
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 
37 
38 
#import "People.h" 
 @implementation  People 
 //不动态添加方法 
+( BOOL ) resolveInstanceMethod: ( SEL ) sel { 
    return  NO ; 
 } 
 //不指定备选响应对象 
-( id ) forwardingTargetForSelector: ( SEL ) aSelector { 
    return  nil ; 
 } 
 //返回方法签名 
-( NSMethodSignature  * ) methodSignatureForSelector: ( SEL ) aSelector { 
    if  ([ NSStringFromSelector ( aSelector )  isEqualToString : @"sing" ])  { 
         return  [ NSMethodSignature  signatureWithObjCTypes : "v@:" ]; 
     } 
     return  [ super  methodSignatureForSelector : aSelector ]; 
 } 
 //修改调用方法 
-( void ) forwardInvocation: ( NSInvocation  * ) anInvocation { 
    [ anInvocation  setSelector : @selector ( dance )]; 
     [ anInvocation  invokeWithTarget : self ]; 
 } 
 //若不实现forwardInvocation,则会调用此方法(可以注释掉forwardInvocation方法来做实验) 
-( void ) doesNotRecognizeSelector: ( SEL ) aSelector { 
    NSLog ( @"消息无法处理:%@" , NSStringFromSelector ( aSelector )); 
 } 
 -( void ) dance { 
    NSLog ( @"跳舞中" ); 
 } 
 @end 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
#import <Foundation/Foundation.h> 
#import "People.h" 
#import <objc/runtime.h> 
#import <objc/message.h> 
 int  main ( int  argc ,  const  char  *  argv [])  { 
    @autoreleasepool  { 
         People *  p  =  [[ People  alloc ] init ]; 
         [ p  sing ]; 
     } 
     return  0 ; 
 } 
打印结果: 
1 
2 
2016 - 05 - 13  11 : 33 : 01.871  runtime  之  消息动态解析 ( 三 )[ 3073 : 329356 ]  跳舞中 
Program  ended  with  exit  code :  0 
以上demo地址 
参考文章:  Objective-C Runtime 1小时入门教程   详解Runtime运行时机制