runtime主要有一下几种应用场景
- 方法交换
- 添加属性
(一)方法交换
(1)字体适配
//获取实例方法
Method n = class_getInstanceMethod(<#Class _Nullable __unsafe_unretained cls#>, <#SEL _Nonnull name#>)
//获取类方法
Method m = class_getClassMethod(<#Class _Nullable __unsafe_unretained cls#>, <#SEL _Nonnull name#>)
//交换方法
method_exchangeImplementations(<#Method _Nonnull m1#>, <#Method _Nonnull m2#>)
方法交换实际交换的是方法实现的地址
//load方法不需要手动调用,iOS会在应用程序启动的时候自动调起load方法,而且执行时间较早,所以在此方法中执行交换操作比较合适。
+ (void)load {
Method orignal = class_getClassMethod([self class], @selector(systemFontOfSize:));
Method mjfont = class_getClassMethod([self class], @selector(mjfontOfSize:));
method_exchangeImplementations(orignal, mjfont);
}
+ (UIFont *)mjfontOfSize:(CGFloat)size {
if (ScreenWidth == 375) {
return [self mjfontOfSize:size];
}
return [self mjfontOfSize:size + 10];
}
(2)button防止重复点击
①在.h文件中声明时间属性,用于设置多长时间不能重复点击
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIButton (Category)
@property (nonatomic, assign) NSTimeInterval timerInterval;
@property (nonatomic, assign) BOOL isOk;
@end
②在.m文件中声明是否可以点击属性
#import "UIButton+Category.h"
#import <objc/runtime.h>
@interface UIButton ()
@property (nonatomic, assign) BOOL isOk;
@end
③添加属性的set、get方法,实现方法交换
+ (void)load {
Method orignal = class_getInstanceMethod([self class], @selector(sendAction:to:forEvent:));
Method mjSend = class_getInstanceMethod([self class], @selector(mjsendAction:to:forEvent:));
method_exchangeImplementations(orignal, mjSend);
}
- (void)mjsendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
if (!self.isOk) {
self.isOk = YES;
[self mjsendAction:action to:target forEvent:event];
//重设是否可以点击
[self performSelector:@selector(resetOK) withObject:nil afterDelay:self.timerInterval];
}
}
- (void)setIsOk:(BOOL)isOk {
objc_setAssociatedObject(self, @selector(isOk), @(isOk), OBJC_ASSOCIATION_ASSIGN);
}
- (BOOL)isOk {
return[objc_getAssociatedObject(self,_cmd)boolValue];
}
- (void)setTimerInterval:(NSTimeInterval)timerInterval {
objc_setAssociatedObject(self, @selector(timerInterval), @(timerInterval), OBJC_ASSOCIATION_ASSIGN);
}
- (NSTimeInterval)timerInterval {
return[objc_getAssociatedObject(self,_cmd)doubleValue];
}
- (void)resetOK {
self.isOk = NO;
}
(二)添加属性---关联对象方法
如:给UIView添加一个name的属性
//①首先声明属性
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIView (Category)
@property (nonatomic, strong) NSString *name;
@end
NS_ASSUME_NONNULL_END
②添加set、get方法实现
#import "UIView+Category.h"
#import <objc/runtime.h>
@implementation UIView (Category)
/*
object 需要设置关联属性的对象,即给谁关联属性
key 关联属性对应的key,可通过key获取这个属性
value 给关联属性设置的值
objc_AssociationPolicy policy 关联属性的存储协议
*/
objc_setAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>, <#id _Nullable value#>, <#objc_AssociationPolicy policy#>)
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY);
}
/*
object 需要关联属性的对象,即给谁关联属性
value 关联属性对应的key,可以通过这个key找到关联属性
*/
objc_getAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>)
- (NSString *)name {
return objc_getAssociatedObject(self, @selector(name));
}
@end
网友评论