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
[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