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 |
利用runtime拦截系统类对象方法调用
Leave a reply