iOS-避免数组崩溃(Method Swizzling)

2018-02-08 10:26:09来源:https://www.jianshu.com/p/aa3285bc5ee2作者:linbj人点击

分享


在项目开发过程中,经常因为NSArray数组越界或者value值为nil等问题导致的崩溃,
直接对NSArray进行Method Swizzling 是没用的,需要对对应的类进行操作才行。


数组是一个类簇从NSArray看类簇


有如下几种类型,对他们分别进行Method Swizzling之后能够一定避免由于数组越界导致的崩溃。


    NSArray *arr1 =  [NSArray alloc];
NSArray *arr2 = [[NSArray alloc]init];
NSArray *arr3 = @[@"1",@"2"];
NSArray *arr4 = [[NSArray alloc]initWithObjects:@"1",nil];
NSArray *arr5 = @[];
NSLog(@"obj1:%@",[arr1 class]);
NSLog(@"obj2:%@",[arr2 class]);
NSLog(@"obj3:%@",[arr3 class]);
NSLog(@"obj4:%@",[arr4 class]);
NSLog(@"obj5:%@",[arr5 class]);
2018-01-30 14:20:04.272322 tesssss[1669:751109] obj1:__NSPlaceholderArray
2018-01-30 14:20:04.272409 tesssss[1669:751109] obj2:__NSArray0
2018-01-30 14:20:04.272441 tesssss[1669:751109] obj3:__NSArrayI
2018-01-30 14:20:04.272471 tesssss[1669:751109] obj4:__NSSingleObjectArrayI
2018-01-30 14:20:04.272497 tesssss[1669:751109] obj5:__NSArray0

NSArray类簇包含了__NSPlaceholderArray,__NSArray0,__NSArrayI这三种类型。


举一个类方法和静态方法例子


#import <Foundation/Foundation.h>
@interface NSArray (AvoidCrash)
+ (void)exchangeClassMethod:(Class)anClass
method1Sel:(SEL)method1Sel
method2Sel:(SEL)method2Sel ;
+ (void)exchangeInstanceMethod:(Class)anClass
method1Sel:(SEL)method1Sel
method2Sel:(SEL)method2Sel ;
@end


#import "NSArray+AvoidCrash.h"
#import <objc/runtime.h>
@implementation NSArray (AvoidCrash)
/**
* 类方法的交换
*
* @param anClass 哪个类
* @param method1Sel 方法1
* @param method2Sel 方法2
*/
+ (void)exchangeClassMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel {
Method method1 = class_getClassMethod(anClass, method1Sel);
Method method2 = class_getClassMethod(anClass, method2Sel);
method_exchangeImplementations(method1, method2);
}

/**
* 对象方法的交换
*
* @param anClass 哪个类
* @param method1Sel 方法1(原本的方法)
* @param method2Sel 方法2(要替换成的方法)
*/
+ (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel {
Method originalMethod = class_getInstanceMethod(anClass, method1Sel);
Method swizzledMethod = class_getInstanceMethod(anClass, method2Sel);

BOOL didAddMethod =
class_addMethod(anClass,
method1Sel,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));

if (didAddMethod) {
class_replaceMethod(anClass,
method2Sel,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
}

else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}

}
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self exchangeClassMethod:[self class]
method1Sel:@selector(arrayWithObjects:count:)
method2Sel:@selector(p_ICEAvoidCrashArrayWithObjects:count:)];
[self exchangeInstanceMethod:NSClassFromString(@"__NSArrayI")
method1Sel:@selector(objectsAtIndexes:)
method2Sel:@selector(p_ICEobjectsAtIndexes:)];
});
}

#pragma mark - p_method
+ (instancetype)p_ICEAvoidCrashArrayWithObjects:(const id _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt {
id instanceObject = nil;
@try {
instanceObject = [self p_ICEAvoidCrashArrayWithObjects:objects count:cnt];
}
@catch (NSException *exception) {
// 自定义处理捕捉到的错误
NSLog(@"%@", exception);

// 尝试处理数组的问题
NSInteger indexNew = 0;
id _Nonnull __unsafe_unretained arrNew[cnt];

for (int i = 0; i < cnt; i++) {
if (objects[i] != nil) {
arrNew[indexNew] = objects[i];
indexNew++;
}
}
instanceObject = [self p_ICEAvoidCrashArrayWithObjects:arrNew count:indexNew];
}
@finally {
return instanceObject;
}
}
//__NSArrayI objectAtIndex:
- (id)p_ICEobjectsAtIndexes:(NSUInteger)index {
id object = nil;

@try {
object = [self p_ICEobjectsAtIndexes:index];
}
@catch (NSException *exception) {
// 自定义处理捕捉到的错误
NSLog(@"%@", exception);
}
@finally {
return object;
}
}
@end

iOS-runtime替换实现方法
Baymax:网易iOS App运行时Crash自动防护实践








最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台