iOS-Runtime之数组越界

关于数组越界目前大概有两种方式,一种是通过分类添加安全的索引方法,第二种就是Runtime实现,第一种如果是个人开发比较建议,如果是团队开发很难得到保证和推动,关于Runtime处理数组越界网上有人说是在iOS7及以上有软键盘输入的地方按Home键退出,会出现崩溃,测试过两台手机iOS8.1和iOS9.3暂时没有出现问题,如果之后出现问题会更新文章.

方法交换

Runtime解决数据越界及字典key或value为nil的情况,主要通过Runtime的方法交换实现,可以扩展一下NSObject分类:

@implementationNSObject (FlyElephant)- (void)swizzleMethod:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector{    Classclass= [selfclass];Method originalMethod = class_getInstanceMethod(class,originalSelector);Method swizzledMethod = class_getInstanceMethod(class,swizzledSelector);BOOL didAddMethod = class_addMethod(class,originalSelector,method_getImplementation(swizzledMethod),                                        method_getTypeEncoding(swizzledMethod));if(didAddMethod) {        class_replaceMethod(class,swizzledSelector,method_getImplementation(originalMethod),                            method_getTypeEncoding(originalMethod));    }else{        method_exchangeImplementations(originalMethod, swizzledMethod);    }}@end

现在需要扩展NSArray和NSDictionary分类,实现方法交换:

@implementationNSArray (FlyElephant)+ (void)load{staticdispatch_once_t onceToken;    dispatch_once(&onceToken, ^{@autoreleasepool{            [objc_getClass("__NSArray0")swizzleMethod:@selector(objectAtIndex:)swizzledSelector:@selector(emptyObjectIndex:)];            [objc_getClass("__NSArrayI")swizzleMethod:@selector(objectAtIndex:)swizzledSelector:@selector(arrObjectIndex:)];            [objc_getClass("__NSArrayM")swizzleMethod:@selector(objectAtIndex:)swizzledSelector:@selector(mutableObjectIndex:)];            [objc_getClass("__NSArrayM")swizzleMethod:@selector(insertObject:atIndex:)swizzledSelector:@selector(mutableInsertObject:atIndex:)];        }    });}- (id)emptyObjectIndex:(NSInteger)index{returnnil;}- (id)arrObjectIndex:(NSInteger)index{if(index >= self.count || index <0) {returnnil;    }return[selfarrObjectIndex:index];}- (id)mutableObjectIndex:(NSInteger)index{if(index >= self.count || index <0) {returnnil;    }return[selfmutableObjectIndex:index];}- (void)mutableInsertObject:(id)objectatIndex:(NSUInteger)index{if(object) {        [selfmutableInsertObject:objectatIndex:index];    }}@end@implementationNSDictionary (FlyElephant)+ (void)load{staticdispatch_once_t onceToken;    dispatch_once(&onceToken, ^{@autoreleasepool{            [objc_getClass("__NSDictionaryM")swizzleMethod:@selector(setObject:forKey:)swizzledSelector:@selector(mutableSetObject:forKey:)];        }    });}- (void)mutableSetObject:(id)objforKey:(NSString *)key{if(obj && key) {        [selfmutableSetObject:objforKey:key];    }}@end

注意NSArray0表示一般空数组,NSArrayI表示一般数组,__NSArrayM可变数组,NSArray和NSMutableArray相当于工厂,最终实现通过上面三个类进行实现的,有兴趣的可以自行了解一下类簇.

测试

测试代码:

NSArray*emptyArr = [NSArraynew];NSLog(@"%@",[emptyArr objectAtIndex:10]);NSArray*arr = @[@"FlyElephant",@"keso"];NSString*result = [arr objectAtIndex:10];NSLog(@"%@",result);NSMutableArray*mutableArr = [[NSMutableArrayalloc] initWithArray:arr];NSLog(@"%@", mutableArr[100]);NSString*obj;    [mutableArr addObject:obj];//NSDictionaryNSString*dictValue;NSMutableDictionary*mutableDict = [NSMutableDictionarydictionary];    [mutableDict setValue:dictValue forKey:@"FlyElephant"];    [mutableDict setObject:dictValue forKey:dictValue];NSLog(@"%@",mutableDict);

2016.08.17更新

昨天测试的时候还没有问题,今天早上运行项目发现一个莫名其妙的问题:

**[UIKeyboardLayoutStar release]: message senttodeallocatedinstance0x1459e0600**

通过Runtime进行对数组字典进行方法交换之后,之前对键盘输入的场景没有完全弄清楚,完整过程应该是,文本框输入文字→Home键进入后台→点击App图标重新进入→崩溃,有的时候前两步就直接崩溃了,因此Runtime的这个文件需要通过mrc管理:

一般项目都是 ARC 模式,需要单独问Runtime的这个问题添加MRC支持,

Build Phases -> Compile Sources找到文件设置 -fno-objc-arc 标签。

如果项目是MRC 模式,则为 ARC 模式的代码文件加入 -fobjc-arc 标签.

同时可以为相应的代码块添加autoreleasepool:

@autoreleasepool {if(index >=self.count||index <0) {returnnil;        }return[selfarrObjectIndex:index];    }

作者:FlyElephant

链接:http://www.jianshu.com/p/5492d2d3342b

你可能感兴趣的:(iOS-Runtime之数组越界)