当我们想要给一个系统类添加一个属性的时候,假如不用继承的方式去实现,我们应该怎么办呢。有朋友想到了分类category,但是category是不能为系统类添加新的成员变量的,我们可以再category中@property出来一个属性,但是他并不能生成带下划线的成员变量,也不能自动生成该变量的Setter和getter方法。实际上我们可以用runtime去实现为一个类的category添加新的属性并生成setter和getter方法。
本文通过一个实例去讲述如何给category添加一个属性
实例要求:给UIButton自定义一个方法初始化方法,通过Block去实现button绑定的事件。
关联对象:runtime给我们提供了如下的方法
//关联对象
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
//获取关联的对象
id objc_getAssociatedObject(id object, const void *key)
//移除关联的对象
void objc_removeAssociatedObjects(id object)
参数说明:
id object:被关联的对象(如xiaoming)
const void *key:关联的key,要求唯一
id value:关联的对象(如dog)
objc_AssociationPolicy policy:内存管理的策略
内存管理策略:
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.* The association is made atomically. */
当对象给释放时会根据你所选择的策略来决定是否释放关联的对象,值得注意的是,我们不需要主动调用removeAssociated来接触关联的对象,如果需要解除指定的对象,可以使用setAssociatedObject置nil来实现。
UIButton+Block.h
//// UIButton+Block.h// ButtonBlock//// Created by 朱佳男 on 2018/1/5.// Copyright © 2018年 ShangYuKeJi. All rights reserved.//
#import <UIKit/UIKit.h>
typedef void (^ButtonActionBlock)(UIButton *button);
@interface UIButton (Block)
+(UIButton *)creatButtonWithFrame:(CGRect)frame title:(NSString *)title actionBlock:(ButtonActionBlock)actionBlock;
@end
UIButton+Block.m
//// UIButton+Block.m// ButtonBlock//// Created by 朱佳男 on 2018/1/5.// Copyright © 2018年 ShangYuKeJi. All rights reserved.//
#import "UIButton+Block.h"
#import <objc/message.h>
static const char *key = "actionKey";
@implementation UIButton (Block)
+(UIButton *)creatButtonWithFrame:(CGRect)frame title:(NSString *)title actionBlock:(ButtonActionBlock)actionBlock{
UIButton *button = [[UIButton alloc]init];
button.frame = frame;
[button setTitle:title forState:UIControlStateNormal];
[button addTarget:button action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
objc_setAssociatedObject(button, key, actionBlock, OBJC_ASSOCIATION_COPY);
return button;
}
-(void)buttonClick:(UIButton *)button{
ButtonActionBlock actionBlock1 = objc_getAssociatedObject(button, key);
if (actionBlock1) {
actionBlock1(button);
}
}
@end
使用方法
UIButton *button = [UIButton creatButtonWithFrame:CGRectMake(100, 100, 100, 44) title:@"我是按钮" actionBlock:^(UIButton *button) {
NSLog(@"我被点击了");
}];
button.backgroundColor = [UIColor orangeColor];
[self.view addSubview:button];
另一种写法
UIButton+Block.h
// UIButton+Block.h// ButtonBlock//// Created by 朱佳男 on 2018/1/5.// Copyright © 2018年 ShangYuKeJi. All rights reserved.//
#import<UIKit/UIKit.h>
typedef void (^ButtonActionBlock)(UIButton *button);
@interface UIButton (Block)
@property (nonatomic ,copy)ButtonActionBlock actionBlock;
+(UIButton *)creatButtonWithFrame:(CGRect)frame title:(NSString *)title actionBlock:(ButtonActionBlock)actionBlock;
@end
UIButton+Block.m
// UIButton+Block.m// ButtonBlock//// Created by 朱佳男 on 2018/1/5.// Copyright © 2018年 ShangYuKeJi. All rights reserved.
#import "UIButton+Block.h"
#import<objc/message.h>
static const char *key2 = "propertyKey";
@implementation UIButton (Block)
+(UIButton *)creatButtonWithFrame:(CGRect)frame title:(NSString *)title actionBlock:(ButtonActionBlock)actionBlock{
UIButton *button = [[UIButton alloc]init];
button.frame = frame;
[button setTitle:title forState:UIControlStateNormal];
[button addTarget:button action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
return button;
}
-(void)buttonClick:(UIButton *)button{
ButtonActionBlock actionBlock2 = self.actionBlock;
if (actionBlock2) {
actionBlock2(button);
}
}
-(void)setActionBlock:(ButtonActionBlock)actionBlock{
objc_setAssociatedObject(self, key2, actionBlock, OBJC_ASSOCIATION_COPY);
}
-(ButtonActionBlock)actionBlock{
return objc_getAssociatedObject(self, key2);
}
@end
使用方法
UIButton *button2 = [UIButton creatButtonWithFrame:CGRectMake(100, 200, 100, 44) title:@"我也是按钮" actionBlock:nil];
button2.actionBlock = ^(UIButton *button) {
NSLog(@"我也被点击了");
};
button2.backgroundColor = [UIColor orangeColor];
[self.view addSubview:button2];