一、给分类加属性 分类中添加属性, .m文件中不会自动生成set及get方法, 需要在运行时进行关联绑定;
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
object:关联的源对象, key:关联此对象的标识, value:关联的对象 policy:关联策略,此处block属性用的copy, 关联策略就使用了 OBJC_ASSOCIATION_COPY_NONATOMIC
.h 中
typedef void(^TouchEvent)(UIButton *obj);
//给分类加block属性
@property (nonatomic, copy) TouchEvent event;
.m 中
static char *btn = "UIControlEventTouchUpInside";
- (void)setEvent:(TouchEvent)event {
objc_setAssociatedObject(self, &btn, event, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
//源对象根据key标识就能获取关联对象
- (TouchEvent)event {
return objc_getAssociatedObject(self, &btn);
}
二、关联对象 利用runtime可以把两个属性关联起来, 一个属性根据标识就能获取到另外一个对象
Person *per = [[Person alloc] init];
per.name = @"张三";
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame =CGRectMake(30, 30, 60, 30);
[btn setTitle:@"点击" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
//把对象per关联到btn上面
objc_setAssociatedObject(btn, "btn", per, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- (void)clickBtn:(UIButton *)sender {
Person *per = (Person *)objc_getAssociatedObject(sender, "btn");
NSLog(@"===%@", per.name);
}
打印结果:
===张三
三、特殊情况下方法替换
method swizzling可以通过选择器来改变它引用的函数指针,从而实现方法替换
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewWillAppear:);
SEL swizzledSelector = @selector(sro_viewWillAppear:);
//获取实例方法
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
- (void)sro_viewWillAppear:(BOOL)animated {
//下面这段代码并没有死循环, method指针已经被替换, 会调用viewWillAppear方法
[self sro_viewWillAppear:animated];
NSLog(@"viewWillAppear: %@", self);
}
runtime在特殊的情况下还是很有用的,进一步学习中~