美文网首页
iOS 感受黑魔法Method Swizzling的魅力(二)

iOS 感受黑魔法Method Swizzling的魅力(二)

作者: Hem1ngTai | 来源:发表于2019-08-08 10:26 被阅读0次

上一篇介绍了Method Swizzling的相关方法,也介绍了一些常用场景,今天就详细介绍一下如何使用Method Swizzling来拦截系统常见崩溃,感受Method Swizzling带来的真正魅力。

要拦截系统常见的崩溃,诸如数组越界,截取子串,插入空值等,就要先交换系统的方法,再去拦截系统抛出的异常信息,举个🌰,现在要截取数组越界的崩溃,看代码:

NSArray *array = @[@"1",@"2",@"3"];
NSLog(@"%@", array[3]);

正常情况下,这段代码是肯定会崩溃的,看控制台输出的崩溃信息:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndexedSubscript:]: index 3 beyond bounds [0 .. 2]'

现在我们要拦截这个崩溃,首先在调用objectAtIndexdSubscript方法之前(我们调用array[3]本质上就是调用objectAtIndexdSubscript),我们要先交换这个方法,看代码:

+ (void)ht_interceptArrayCrashCausedByIndexBeyondBounds {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    Class clsI = NSClassFromString(@"__NSArrayI");
    [HTCrashReporter ht_swizzleInstanceMethodForClass:clsI
                                     originalSelector:@selector(objectAtIndexedSubscript:)
                                    swizzlingSelector:@selector(ht_objectAtIndexedSubscriptI:)];
    });
}

- (id)ht_objectAtIndexedSubscriptI:(NSUInteger)idx {
    id object = nil;
    @try {
        object = [self ht_objectAtIndexedSubscriptI:idx];
    } @catch (NSException *exception) {
        [HTCrashReporter ht_catchException:exception withCrashType:HTCrashTypeArrayIndexBeyondBounds];
    } @finally {
        return object;
    }
}

这里有几点需要注意下:

  • 第一点:交换方法需要写在+load方法里,而且要保证只调用一次(这里不赘述具体原因,有兴趣的小伙伴自行查找);
  • 第二点:我们交换的是对象方法,所以应该调用swizzleInstanceMethod方法而不是swizzleClassMethod方法;
  • 第三点:🌰中的数组是不可变数组,根据控制台输出信息中提示的是__NSArrayI(两道下划线),所以我们要替换的类是NSClassFromString(@"__NSArrayI")
  • 第四点:有的小伙伴可能会有疑问,为什么在交换的方法里还要调用当前方法,这不就死循环了吗?非也,这里看上去调用当前方法,但是实质上内部方法的实现是系统方法的实现,所以这里使用了try catch语句,因为数组越界,系统方法会抛出异常,这里捕获异常再做进一步处理,比如上传服务器。到这里就实现了拦截了数据越界引起的崩溃,程序不会闪退还是可以正常运行。

上面只是一个简单的🌰,HTCrashReporter做了NSString,NSArray,NSDictionary,NSObject常见崩溃拦截,欢迎各位大佬指正,不介意动动手指请赏个Star。

相关文章

网友评论

      本文标题:iOS 感受黑魔法Method Swizzling的魅力(二)

      本文链接:https://www.haomeiwen.com/subject/sqvndctx.html