#import "NSMutableDictionary+NullSafe.h"
@implementation NSMutableDictionary (NullSafe)
- (void)swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
Class class = [self class];
//得到類的實(shí)例方法
Method originalMethod = class_getInstanceMethod(class, origSelector);
Method swizzledMethod = class_getInstanceMethod(class, newSelector);
//向class類中添加 test:方法;函數(shù)簽名為@@:@,
//? ? 第一個(gè)@本class,
//? ? 第二個(gè)@添加的方法在本類里面叫做的名字
//? ? 第三個(gè):IMP就是Implementation的縮寫,它是指向一個(gè)方法實(shí)現(xiàn)的指針,每一個(gè)方法都有一個(gè)對應(yīng)的IMP。這里需要的是IMP,所以你不能直接寫方法,需要用到一個(gè)方法class_getMethodImplementation
//? ? 第四個(gè)@表示我們要添加的方法的返回值和參數(shù)。
BOOL didAddMethod = class_addMethod(class,
origSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
//使用該函數(shù)可以在運(yùn)行時(shí)動(dòng)態(tài)替換某個(gè)類的函數(shù)實(shí)現(xiàn),這樣做有什么用呢?最起碼,可以實(shí)現(xiàn)類似windows上hook效果,即截獲系統(tǒng)類的某個(gè)實(shí)例函數(shù),然后塞一些自己的東西進(jìn)去,比如打個(gè)log什么的
class_replaceMethod(class,
newSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
id obj = [[self alloc] init];
[obj swizzleMethod:@selector(setObject:forKey:) withMethod:@selector(safe_setObject:forKey:)];
});
}
- (void)safe_setObject:(id)value forKey:(NSString *)key {
if (value) {
[self safe_setObject:value forKey:key];
}else {
DebugLog(@"[NSMutableDictionary setObject: forKey:], Object cannot be nil")
}
}
這種解決方法可以避免諸如數(shù)組取值越界、字典傳空值、removeObjectAtIndex等錯(cuò)誤,如下的崩潰就可以避免:
id obj = nil;
NSMutableDictionary *m_dict = [NSMutableDictionary dictionary];
[dict setObject:obj forKey:@"666"];