用Method Swizzling來避免陣列越界與可變字典value值為nil造成的程式崩潰
阿新 • • 發佈:2019-02-08
程式崩潰對於app來說是最致命的bug,而陣列越界便是其中最重要的原因之一。我們可以應用Method Swizzling知識來避免這一問題。
1.我們來建立一個類別,繼承於NSArray:
2.然後在.m檔案中匯入 objc/runtime.h標頭檔案
#import "NSArray+EM.h" #import <objc/runtime.h> @implementation NSArray (EM) +(void)load { Method fromMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(objectAtIndex:)); Method toMethod = class_getInstanceMethod(objc_getClass("__NSArrayI"), @selector(em_objectAtIndex:)); method_exchangeImplementations(fromMethod, toMethod); } - (void)em_objectAtIndex:(NSUInteger)index { if (self.count - 1 < index) { @try { return[self em_objectAtIndex:index]; } @catch (NSException *exception) { NSLog(@"-------- %s Crash Because Method %s -------\n",class_getName(self.class),__func__); NSLog(@"%@", [exception callStackSymbols]); } @finally { } }else { return [self em_objectAtIndex:index]; } } @end
細心的人會發現,下面這個方法會導致遞迴,其實不會的。
這實際上是運用了方法替換,當我們在其他類中 呼叫NSArray的objectAtIndex方法時,會被自動替換為執行em_objectAtIndex:方法,而當我們呼叫em_objectAtIndex:方法時,會被替換為執行objectAtIndex:方法。我們也可以用這種方法同樣解決NSMutableArray。
#import "NSMutableArray+EM.h" #import <objc/runtime.h> @implementation NSMutableArray (EM) +(void)load { Method fromMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), @selector(objectAtIndex:)); Method toMethod = class_getInstanceMethod(objc_getClass("__NSArrayM"), @selector(em_objectAtIndex:)); method_exchangeImplementations(fromMethod, toMethod); } - (void)em_objectAtIndex:(NSUInteger)index { if (self.count - 1 < index) { @try { return[self em_objectAtIndex:index]; } @catch (NSException *exception) { NSLog(@"-------- %s Crash Because Method %s -------\n",class_getName(self.class),__func__); NSLog(@"%@", [exception callStackSymbols]); } @finally { } }else { return [self em_objectAtIndex:index]; } } @end
還可以判斷NSMutableDictionary 的value值是否為nil
#import "NSMutableDictionary+EM.h" #import <objc/runtime.h> @implementation NSMutableDictionary (EM) + (void)load { Method fromMethod = class_getInstanceMethod(objc_getClass("__NSDictionaryM"), @selector(setObject:forKey:)); Method toMethod = class_getInstanceMethod(objc_getClass("__NSDictionaryM"), @selector(em_setObject:forKey:)); method_exchangeImplementations(fromMethod, toMethod); } - (void)em_setObject:(id)emObject forKey:(NSString *)key { if (emObject == nil) { @try { [self em_setObject:emObject forKey:key]; } @catch (NSException *exception) { NSLog(@"---------- %s Crash Because Method %s ----------\n", class_getName(self.class), __func__); NSLog(@"%@", [exception callStackSymbols]); emObject = [NSString stringWithFormat:@""]; [self em_setObject:emObject forKey:key]; } @finally {} }else { [self em_setObject:emObject forKey:key]; } } @end
下面我們列舉一些常用的類簇的“真身”: