利用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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#import "ViewController.h"
#import <objc/runtime.h>
 
 
@interface NSMutableArray (SA)
@end
@implementation NSMutableArray (SA)
+ (void)load
{
    static dispatch_once_t onceToken;
    // 单次执行
    dispatch_once(&onceToken, ^{
        // NSArray为类簇,insertObject:atIndex:的实际调用类为__NSArrayM
        Class cls = NSClassFromString(@"__NSArrayM");
        // 交换原方法与自定义方法的实现
        Method origin = class_getInstanceMethod(cls, @selector(insertObject:atIndex:));
        Method hook = class_getInstanceMethod(cls, @selector(sa_insertObject:atIndex:));
        method_exchangeImplementations(origin, hook);
    });
}
// insertObject:atIndex:方法的实际执行
- (void)sa_insertObject:(id)anObject atIndex:(NSUInteger)index
{
    // 1、拦截原方法需要执行的动作在这里实现
    if (anObject == nil) return;
    // 2、调回原方法保证完整性,由于方法实现互换,所以调用当前方法即为调用原方法
    [self sa_insertObject:anObject atIndex:index];
}
@end
 
@interface NSMutableDictionary (SA)
@end
@implementation NSMutableDictionary (SA)
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = NSClassFromString(@"__NSDictionaryM");
        Method origin = class_getInstanceMethod(cls, @selector(setObject:forKey:));
        Method hook = class_getInstanceMethod(cls, @selector(sa_setObject:forKey:));
        method_exchangeImplementations(origin, hook);
    });
}
- (void)sa_setObject:(id)anObject forKey:(id<NSCopying>)aKey
{
    if (anObject == nil) return;
    [self sa_setObject:anObject forKey:aKey];
}
@end
 
@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    NSMutableArray *array = [NSMutableArray array];
    // 验证可变数组添加空对象是否会抛出异常
    [array addObject:nil];
 
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    // 验证可变字典添加空对象是否会抛出异常
    [dict setObject:nil forKey:@"name"];
 
    NSLog(@"---------");
}
 
@end

Leave a Reply