#import "NSMutableDictionary+NullSafe.h"
@implementation NSMutableDictionary (NullSafe)
- (void)swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
Class class = [self class];
//得到类的实例方法
Method originalMethod = class_getInstanceMethod(class, origSelector);
Method swizzledMethod = class_getInstanceMethod(class, newSelector);
//向class类中添加 test:方法;函数签名为@@:@,
// 第一个@本class,
// 第二个@添加的方法在本类里面叫做的名字
// 第三个:IMP就是Implementation的缩写,它是指向一个方法实现的指针,每一个方法都有一个对应的IMP。这里需要的是IMP,所以你不能直接写方法,需要用到一个方法class_getMethodImplementation
// 第四个@表示我们要添加的方法的返回值和参数。
BOOL didAddMethod = class_addMethod(class,
origSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
//使用该函数可以在运行时动态替换某个类的函数实现,这样做有什么用呢?最起码,可以实现类似windows上hook效果,即截获系统类的某个实例函数,然后塞一些自己的东西进去,比如打个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")
}
}
这种解决方法可以避免诸如数组取值越界、字典传空值、removeObjectAtIndex等错误,如下的崩溃就可以避免:
id obj = nil;
NSMutableDictionary *m_dict = [NSMutableDictionary dictionary];
[dict setObject:obj forKey:@"666"];