關(guān)于數(shù)組越界目前大概有兩種方式,一種是通過(guò)分類添加安全的索引方法,第二種就是Runtime實(shí)現(xiàn),第一種如果是個(gè)人開發(fā)比較建議,如果是團(tuán)隊(duì)開發(fā)很難得到保證和推動(dòng),關(guān)于Runtime處理數(shù)組越界網(wǎng)上有人說(shuō)是在iOS7及以上有軟鍵盤輸入的地方按Home鍵退出,會(huì)出現(xiàn)崩潰,測(cè)試過(guò)兩臺(tái)手機(jī)iOS8.1和iOS9.3暫時(shí)沒(méi)有出現(xiàn)問(wèn)題,如果之后出現(xiàn)問(wèn)題會(huì)更新文章.
方法交換
Runtime解決數(shù)據(jù)越界及字典key或value為nil的情況,主要通過(guò)Runtime的方法交換實(shí)現(xiàn),可以擴(kuò)展一下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)在需要擴(kuò)展NSArray和NSDictionary分類,實(shí)現(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)于工廠,最終實(shí)現(xiàn)通過(guò)上面三個(gè)類進(jìn)行實(shí)現(xiàn)的,有興趣的可以自行了解一下類簇.
測(cè)試
測(cè)試代碼:
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更新
昨天測(cè)試的時(shí)候還沒(méi)有問(wèn)題,今天早上運(yùn)行項(xiàng)目發(fā)現(xiàn)一個(gè)莫名其妙的問(wèn)題:
**[UIKeyboardLayoutStar release]: message senttodeallocatedinstance0x1459e0600**
通過(guò)Runtime進(jìn)行對(duì)數(shù)組字典進(jìn)行方法交換之后,之前對(duì)鍵盤輸入的場(chǎng)景沒(méi)有完全弄清楚,完整過(guò)程應(yīng)該是,文本框輸入文字→Home鍵進(jìn)入后臺(tái)→點(diǎn)擊App圖標(biāo)重新進(jìn)入→崩潰,有的時(shí)候前兩步就直接崩潰了,因此Runtime的這個(gè)文件需要通過(guò)mrc管理:
一般項(xiàng)目都是 ARC 模式,需要單獨(dú)問(wèn)Runtime的這個(gè)問(wèn)題添加MRC支持,
Build Phases -> Compile Sources找到文件設(shè)置 -fno-objc-arc 標(biāo)簽。
如果項(xiàng)目是MRC 模式,則為 ARC 模式的代碼文件加入 -fobjc-arc 標(biāo)簽.
同時(shí)可以為相應(yīng)的代碼塊添加autoreleasepool:
@autoreleasepool {if(index >=self.count||index <0) {returnnil;? ? ? ? }return[selfarrObjectIndex:index];? ? }
作者:FlyElephant
鏈接:http://www.itdecent.cn/p/5492d2d3342b