- load 的应用
load
可以说我们在日常开发中可以接触到的调用时间
最靠前的方法,在主函数运行之前,
load
方法就会调用。
由于它的调用不是惰性的,且其只会在程序调用期间调用一次,最最重要的是,如果在类与分类中都实现了 load
方法,它们都会被调用,不像其它的在分类中实现的方法会被覆盖,这就使 load
方法成为了方法调剂的绝佳时机。
但是由于 load
方法的运行时间过早,所以这里可能不是一个理想的环境,因为某些类可能需要在在其它类之前加载,但是这是我们无法保证的。不过在这个时间点,所有的 framework 都已经加载到了运行时中,所以调用 framework 中的方法都是安全的。
Method 和 IMP 的分别
Method 是类似 @selector(method:) 的形式,而 IMP 则是方法实际指向的地址
需要掌握的objc runtime的方法,其他的方法可以在文档中查看https://developer.apple.com/reference/objectivec/1657527-objective_c_runtime
class_getInstanceMethod
class_getClassMethod
method_exchangeImplementations
class_replaceMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>)
现在以一个例子来叙述
防止UIButton重复点击
import <UIKit/UIKit.h>
@interface UIButton (RepeatAction)
@property (nonatomic,assign) NSTimeInterval repeat_acceptEventInterval;
@property (nonatomic,assign) BOOL repeat_ignoreEvent;
@end
#import "UIButton+RepeatAction.h"
#import <objc/runtime.h>
@implementation UIButton (RepeatAction)
static const char * UIControl_acceptEventInterval = "UIControl_acceptEventInterval";
static const char * UIControl_ignoreEvent = "UIControl_ignoreEvent";
- (NSTimeInterval)repeat_acceptEventInterval {
return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
}
- (void)setRepeat_acceptEventInterval:(NSTimeInterval)repeat_acceptEventInterval{
objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(repeat_acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)repeat_ignoreEvent {
return [objc_getAssociatedObject(self, UIControl_ignoreEvent) boolValue];
}
- (void)setRepeat_ignoreEvent:(BOOL)repeat_ignoreEvent {
objc_setAssociatedObject(self, UIControl_ignoreEvent, @(repeat_ignoreEvent), OBJC_ASSOCIATION_ASSIGN);
}
- (void)__repeat_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
if (self.repeat_ignoreEvent) {
return;
}
if (self.repeat_acceptEventInterval > 0) {
self.repeat_ignoreEvent = YES;
[self performSelector:@selector(setRepeat_ignoreEvent:) withObject:@(NO) afterDelay:self.repeat_acceptEventInterval];
}
[self __repeat_sendAction:action to:target forEvent:event];
}
+ (void)load {
Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method b = class_getInstanceMethod(self, @selector(__repeat_sendAction:to:forEvent:));
method_exchangeImplementations(a, b);
}
//预防UITabbarButton 报错
- (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
[super sendAction:action to:target forEvent:event];
}
@end
调用的时候,直接
微博:Freddie被占用了