關(guān)于數(shù)組越界目前大概有兩種方式翠肘,一種是通過分類添加安全的索引方法腰素,第二種就是Runtime實現(xiàn)芦倒,第一種如果是個人開發(fā)比較建議,如果是團隊開發(fā)很難得到保證和推動赴叹,關(guān)于Runtime處理數(shù)組越界網(wǎng)上有人說是在iOS7及以上有軟鍵盤輸入的地方按Home鍵退出鸿染,會出現(xiàn)崩潰,測試過兩臺手機iOS8.1和iOS9.3暫時沒有出現(xiàn)問題乞巧,如果之后出現(xiàn)問題會更新文章.
方法交換
Runtime解決數(shù)據(jù)越界及字典key或value為nil的情況涨椒,主要通過Runtime的方法交換實現(xiàn),可以擴展一下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
現(xiàn)在需要擴展NSArray和NSDictionary分類绽媒,實現(xiàn)方法交換:
@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表示一般空數(shù)組蚕冬,NSArrayI表示一般數(shù)組,__NSArrayM可變數(shù)組是辕,NSArray和NSMutableArray相當(dāng)于工廠囤热,最終實現(xiàn)通過上面三個類進行實現(xiàn)的,有興趣的可以自行了解一下類簇.
測試
測試代碼:
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更新
昨天測試的時候還沒有問題获三,今天早上運行項目發(fā)現(xiàn)一個莫名其妙的問題:
**[UIKeyboardLayoutStar release]: message senttodeallocatedinstance0x1459e0600**
通過Runtime進行對數(shù)組字典進行方法交換之后旁蔼,之前對鍵盤輸入的場景沒有完全弄清楚锨苏,完整過程應(yīng)該是,文本框輸入文字→Home鍵進入后臺→點擊App圖標重新進入→崩潰棺聊,有的時候前兩步就直接崩潰了伞租,因此Runtime的這個文件需要通過mrc管理:
一般項目都是 ARC 模式,需要單獨問Runtime的這個問題添加MRC支持限佩,
Build Phases -> Compile Sources找到文件設(shè)置 -fno-objc-arc 標簽葵诈。
如果項目是MRC 模式,則為 ARC 模式的代碼文件加入 -fobjc-arc 標簽.
同時可以為相應(yīng)的代碼塊添加autoreleasepool:
@autoreleasepool {if(index >=self.count||index <0) {returnnil;? ? ? ? }return[selfarrObjectIndex:index];? ? }
作者:FlyElephant
鏈接:http://www.reibang.com/p/5492d2d3342b