iOS底层原理runtime 方法列表 以及常用api调用

runtime的基本使用和一些方法列表,以及应用

Posted by gongkuihua on May 28, 2019

#iOS底层原理runtime 方法列表 以及常用api调用

objc_系列函数关注于宏观使用,如类与协议的空间分配,注册,注销等操作

class_系列函数关注于类的内部,如实例变量,属性,方法,协议等相关问题

objcet_系列函数关注于对象的角度,如实例变量

method_系列函数关注于方法内部,如果方法的参数及返回值类型和方法的实现

property_系类函数关注与属性*内部,如属性的特性等

protocol_系类函数关注与协议相关 ivar_xxx函数关注与实例变量的东西

sel_xxx主要讨论关于方法编号相关的东西

imp_xxx主要讨论关于方法实现相关的

#下面我们来玩一下这些常用的api

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//交换方法
        Method m1 = class_getInstanceMethod(self, @selector(viewWillAppear:));
        Method m2 = class_getInstanceMethod(self, @selector(tz_viewWillAppear:));        
        method_exchangeImplementations(m1, m2);
// 关联属性
- (void)setViewColor:(NSString *)viewColor{
    
    objc_setAssociatedObject(self, &associatedObjectKey, @"addProperty", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSString *)viewColor{
    return objc_getAssociatedObject(self, &associatedObjectKey);
}

 /// 创建一类对
    Class TZCat = objc_allocateClassPair([NSObject class], "TZCat", 0);
    
    /// 添加实例变量
    // const char* types= "v@:"
    NSString* name = @"name";
   
    class_addIvar(TZCat, name.UTF8String, sizeof(id), log2(sizeof(id)), @encode(id));
    
    // 添加方法
    class_addMethod(TZCat, @selector(hunting), (IMP)hunting, "v@:");
    
    /// 注册类
    objc_registerClassPair(TZCat);
    
    
    // 创建实例对象
    id cat = [[TZCat alloc] init];
    [cat setValue:@"Tom" forKey:@"name"];
    NSLog(@"name = %@", [cat valueForKey:name]);
    
    /// 方法调用
    [cat performSelector:@selector(hunting)];

  // 获取成员变量列表
    unsigned int count = 0;
    Ivar* ivars = class_copyIvarList([self class], &count);
    
    for (int i = 0; i < count; i++) {
        Ivar var = ivars[i];
        const char* name = ivar_getName(var);
        NSString* key = [NSString stringWithUTF8String:name];
        id value = [self valueForKey:key];
        [aCoder encodeObject:value forKey:key];
    }
    
    free(ivars); #消息转发机制 ![](https://upload-images.jianshu.io/upload_images/7980283-06dc49c206acc445.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000)
/*
 * 第一步 实例方法专用  方法解析
 **/

+ (BOOL)resolveInstanceMethod:(SEL)sel{

    NSLog(@"%@",NSStringFromSelector(sel));

    if(sel == @selector(DoThings:Num:)){
        class_addMethod([self class], sel, (IMP)MyMethodIMP, "v@:");
        return YES;
    }

    return  [super resolveInstanceMethod:sel];
}

/*
 * 第二步 如果第一步未处理,那么让别的对象去处理这个方法
 **/
-(id)forwardingTargetForSelector:(SEL)aSelector{

    if([NSStringFromSelector(aSelector) isEqualToString:@"DoThings:Num:"]){
        return [[Tools alloc]init];
    }
    return [super forwardingTargetForSelector:aSelector];
}

/*
 * 第三步 如果前两步未处理,这是最后处理的机会将目标函数以其他形式执行
 **/
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
  
    NSString *SelStr = NSStringFromSelector(aSelector);
    if([SelStr isEqualToString:@"DoThings:Num:"]){
        [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}

-(void)forwardInvocation:(NSInvocation *)anInvocation{

    //改变消息接受者对象
    [anInvocation invokeWithTarget:[[Tools alloc]init]];
    
    //改变消息的SEL
    anInvocation.selector = @selector(flyGame);
    [anInvocation invokeWithTarget:self];
    
}

- (void)flyGame{
    
    NSLog(@"我要飞翔追逐梦想!");
    
}

/*
 * 作为找不到函数实现的最后一步,NSObject实现这个函数只有一个功能,就是抛出异常。
 * 虽然理论上可以重载这个函数实现保证不抛出异常(不调用super实现),但是苹果文档着重提出“一定不能让这个函数就这么结束掉,必须抛出异常”。
 *
 ***/
- (void)doesNotRecognizeSelector:(SEL)aSelector{

} #消息机制
objc_msgSend("对象","SEL","参数"...)
objc_msgSend( id self, SEL op, ... ) runtime 源码地址:[https://github.com/gongkuihua/objc4-750-master](https://github.com/gongkuihua/objc4-750-master) >[来源地址](https://developer.apple.com/documentation/objectivec/objective-c_runtime?language=objc)