案例一:避免向一个数组中加入nil时导致崩溃
- 交换方法实现
swizzle
(+load 和 dispatch_once_t 能有效保证安全);
- 获取类的实例方法
class_getInstanceMethod
,对应获取类的类方法class_getClassMethod
+(void)load{
[self swizzleMethod:@selector(addObject:) anotherMethod:@selector(safeAddObject:)];
}
+ (void)swizzleMethod:(SEL)oneSel anotherMethod:(SEL)anotherSel{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method oneMethod = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), oneself);//类的真名
Method anotherMethod = class_getInstanceMethod(self, anotherSel);
if (!oneMethod || !anotherMethod) return;
method_exchangeImplementations(oneMethod, anotherMethod);
});
}
- (void)safeAddObject:(id)obj {
if (obj != nil) {
[self safeAddObject:obj];//不会导致递归
} else {
NSLog(@"数组不能加入nil object");
}
}
@end
案例二:防止按钮重复点击
#import "UIControl+Safety.h"
#import <objc/runtime.h>
static const char kSafety_ignoreEventTime;//按钮点击的时间
static const char kSafety_acceptEventInterval;//按钮点击的时间间隔
@interface UIControl ()
@property (nonatomic, assign) NSTimeInterval safety_ignoreEventTime;
@end
@implementation UIControl (Safety)
+(void)load {
[self swizzleMethod:@selector(sendAction:to:forEvent:) anotherMethod:@selector(safety_sendAction:to:forEvent:)];
}
+ (void)swizzleMethod:(SEL)oneSel anotherMethod:(SEL)anotherSel {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method oneMethod = class_getInstanceMethod(self, oneSel);
Method anotherMethod = class_getInstanceMethod(self, anotherSel);
if (!oneMethod || !anotherMethod) return;
method_exchangeImplementations(oneMethod, anotherMethod);
});
}
- (void)safety_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
if (NSDate.date.timeIntervalSince1970 - self.safety_ignoreEventTime < self.safety_acceptEventInterval) {
return;
}
if (self.safety_acceptEventInterval > 0) {
self.safety_ignoreEventTime = NSDate.date.timeIntervalSince1970;
}
[self safety_sendAction:action to:target forEvent:event];
}
#pragma mark property 关联属性
- (NSTimeInterval)safety_ignoreEventTime {
return [objc_getAssociatedObject(self, &kSafety_ignoreEventTime) doubleValue];
}
- (void)setSafety_ignoreEventTime:(NSTimeInterval)safety_ignoreEventTime {
objc_setAssociatedObject(self, &kSafety_ignoreEventTime, @(safety_ignoreEventTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSTimeInterval)safety_acceptEventInterval {
return [objc_getAssociatedObject(self, &kSafety_acceptEventInterval) doubleValue];
}
- (void)setSafety_acceptEventInterval:(NSTimeInterval)safety_acceptEventInterval {
objc_setAssociatedObject(self, &kSafety_acceptEventInterval, @(safety_acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
案例三:字典转模型原理