利用runtime来实现一个数组防崩溃替换

前言

很多时候,我们常常在使用数组的时候因为数组越界而导致程序崩溃。我们通过runtime中的特殊手段,实现在运行时互换函数,达到偷天换日效果。

Method Swizzling

Method Swizzling是发生在运行时期的,主要是在运行时,将两个Method交换。达到偷天换日的效果,Method Swizzling是面向切面编程的一种技术。

OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2) 
 __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
#import 
/**
 *  不可变数组防越界崩溃处理
 */
@interface NSArray (AXKArray)

@end
#import "NSArray+AXKArray.h"
#import 

@implementation NSArray (AXKArray)

+ (void)load
{
    [super load];
    Method originalMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:));
    Method userMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(axk_objectAtIndex:));
    if (!class_addMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:), method_getImplementation(userMethod), method_getTypeEncoding(userMethod))) {
         method_exchangeImplementations(originalMethod, userMethod);
    }
}
- (id)axk_objectAtIndex:(NSUInteger)index
{
    if (self.count - 1 < index) {
        //异常处理,捕获异常并抛出异
        @try {
            return [self axk_objectAtIndex:index];
        }
        @catch (NSException *exception) {
            NSLog(@"不可变数组越界访问异常--%s--Crash Because Method--%s---以上异常", class_getName(self.class), __func__);
            NSLog(@"异常下标--%lu--", index);
            NSLog(@"不可变数组越界访问异常日志%@", [exception callStackSymbols]);
            return nil;
        }
        @finally {
            
        }
    } else {
        return [self axk_objectAtIndex:index];
    }
}
@end

类簇、替身、真身

在iOS中存在大量的有关类簇、真身、替身相关的类等

大家发现了吗,__NSArrayI才是NSArray真正的类,而NSMutableArray又不一样。我们可以通过runtime函数获取真正的类:

objc_getClass("__NSArrayI")
下面我们列举一些常用的类簇的“真身”:

真身
NSArray __NSArrayI
NSMutableArray __NSArrayM
NSDictionary __NSDictionaryI
NSMutableDictionary __NSDictionaryM

Method Swizzling方法只能对替身的真身有效,对替身没有效果。

你可能感兴趣的:(利用runtime来实现一个数组防崩溃替换)