1. 程式人生 > >ios 針對陣列越界的崩潰優化

ios 針對陣列越界的崩潰優化

陣列越界是常見的崩潰 , 崩潰日記是類似這樣的 :

Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 22 beyond bounds for empty NSArray'

網上也找過怎麼解決,但是都不是太徹底, 由於 NSArray是一個類簇,需要把所有的入口都封住才算完美 . 方法還是很常見的,用了runtime的方法替換 . 然後 給NSArray加類別 , 部分核心程式碼:

@implementation NSArray (SafeIndex)


+ (void)load{

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

// NSArray 是一個類簇,具體有三個子類__NSArray0,__NSSingleObjectArrayI,__NSArrayI,

// 還有一個__NSPlaceholderArray是佔位的,不實際使用

// 對__NSArray0,__NSSingleObjectArrayI來說,下面三種呼叫的同一個方法objectAtIndex

/** 對__NSArrayI,__NSArrayM來說,objectAtIndex 和 objectAtIndexedSubscript 有不同的實現,

array[22]呼叫了objectAtIndexedSubscript */

//[array objectAtIndex:22];

//[array objectAtIndexedSubscript:22];

//array[22];

[objc_getClass("__NSArray0") gl_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(emptyObjectIndex:)];

[objc_getClass("__NSSingleObjectArrayI") gl_swizzleMethod:@selector(objectAtIndex:) withMethod

:@selector(singleObjectIndex:)];

[objc_getClass("__NSArrayI") gl_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(safe_arrObjectIndex:)];

[objc_getClass("__NSArrayI") gl_swizzleMethod:@selector(objectAtIndexedSubscript:) withMethod:@selector(safe_objectAtIndexedSubscript:)];

[objc_getClass("__NSArrayM") gl_swizzleMethod:@selector(objectAtIndex:) withMethod:@selector(safeObjectIndex:)];

[objc_getClass("__NSArrayM") gl_swizzleMethod:@selector(objectAtIndexedSubscript:) withMethod:@selector(mutableArray_safe_objectAtIndexedSubscript:)];

[objc_getClass("__NSArrayM") gl_swizzleMethod:@selector(insertObject:atIndex:) withMethod:@selector(safeInsertObject:atIndex:)];

[objc_getClass("__NSArrayM") gl_swizzleMethod:@selector(addObject:) withMethod:@selector(safeAddObject:)];

});

}

- (id)emptyObjectIndex:(NSInteger)index {

NSLog(@"__NSArray0 取一個空陣列 objectAtIndex , 崩潰") ;

returnnil;

}

- (id)singleObjectIndex:(NSInteger)index {

if (index >= self.count || index < 0) {

NSLog(@"__NSSingleObjectArrayI 取一個不可變單元素陣列時越界 objectAtIndex , 崩潰") ;

return nil;

}

return [selfsingleObjectIndex:index];

}

- (id)safe_arrObjectIndex:(NSInteger)index{

if (index >= self.count || index < 0) {

NSLog(@"__NSArrayI 取不可變陣列時越界 objectAtIndex , 崩潰") ;

return nil;

}

return [selfsafe_arrObjectIndex:index];

}

- (id)safe_objectAtIndexedSubscript:(NSInteger)index{

if (index >= self.count || index < 0) {

NSLog(@"__NSArrayI 取不可變陣列時越界 objectAtIndexedSubscript , 崩潰") ;

return nil;

}

return [selfsafe_objectAtIndexedSubscript:index];

}

- (id)mutableArray_safe_objectAtIndexedSubscript:(NSInteger)index{

if (index >= self.count || index < 0) {

NSLog(@"__NSArrayM 取可變陣列時越界 objectAtIndexedSubscript , 崩潰") ;

return nil;

}

return [selfmutableArray_safe_objectAtIndexedSubscript:index];

}

- (id)safeObjectIndex:(NSInteger)index{

if (index >= self.count || index < 0) {

NSLog(@"__NSArrayM 取可變陣列時越界 objectAtIndex , 崩潰") ;

return nil;

}

return [selfsafeObjectIndex:index];

}

- (void)safeInsertObject:(id)object atIndex:(NSUInteger)index{

if (index>self.count) {

NSLog(@"__NSArrayM 新增元素越界 insertObject:atIndex: , 崩潰") ;

return ;

}

if (object == nil) {

NSLog(@"__NSArrayM 新增空元素 insertObject:atIndex: , 崩潰") ;

return ;

}

[selfsafeInsertObject:object atIndex:index];

}

- (void)safeAddObject:(id)object {

if (object == nil) {

NSLog(@"__NSArrayM 新增空元素 addObject , 崩潰") ;

return ;

}

[self safeAddObject:object];

}

@end