在初学iOS时,对关联对象感到很疑惑,最近在看有关转场动画时又看到相关代码,觉得有必要记录一下。其中,关联对象的代码如下:
//// .h中
@interface UIViewController (Transition)
@property (nonatomic, strong) MATransition *transition;
@end
//// .m中
@implementation UIViewController (Transition)
- (MATransition *)transition {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setTransition:(MATransition *)transition {
objc_setAssociatedObject(self, @selector(transition), transition, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
上面代码的目的是,在分类中为已经存在的类添加属性。
1. 关联对象的基本使用
在下面的实例中,可以看出关联对象的基本使用过程,我们可以把一个label关联道一个button实例上:
#import "ViewController.h"
// 引入头文件
#import <objc/runtime.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"首页";
self.view.backgroundColor = UIColor.whiteColor;
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
[view removeFromSuperview];
view.backgroundColor = UIColor.whiteColor;
//要关联的对象的键值,一般设置成静态的,用于获取关联对象的值
static char UIButtonKey;
//创建两个需要关联的对象
UIButton * button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 20, 20)];
button.center = self.view.center;
button.backgroundColor = [UIColor redColor];
[self.view addSubview:button];
UILabel * label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 20, 20)];
label.backgroundColor = [UIColor yellowColor];
label.text =@"获取";
//给对象确立关联(让label关联到button上)
objc_setAssociatedObject(button, &UIButtonKey, label, OBJC_ASSOCIATION_RETAIN);
//根据键值获取到关联对象
UILabel * lab = objc_getAssociatedObject(button, &UIButtonKey);
NSLog(@"lab.text = %@",lab.text);
//断开关联
objc_setAssociatedObject(button, &UIButtonKey, nil, OBJC_ASSOCIATION_ASSIGN);
UILabel * lab1 = objc_getAssociatedObject(button, &UIButtonKey);
NSLog(@"断开关联之后的lab1.text = %@",lab1.text);
}
@end
主要方法说明:
// key:要保证全局唯一,key与关联的对象是一一对应关系。必须全局唯一。通常用@selector(methodName)作为key。
// value:要关联的对象。
// policy:关联策略。有五种关联策略。
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);
// objc_AssociationPolicy的值如下
OBJC_ASSOCIATION_ASSIGN 等价于 @property(assign)。
OBJC_ASSOCIATION_RETAIN_NONATOMIC等价于 @property(strong, nonatomic)。
OBJC_ASSOCIATION_COPY_NONATOMIC等价于@property(copy, nonatomic)。
OBJC_ASSOCIATION_RETAIN等价于@property(strong,atomic)。
OBJC_ASSOCIATION_COPY等价于@property(copy, atomic)。
2. 关联对象的应用场景
iOS开发过程中,在正常的类中用@property定义一个属性变量:
@interface DKObject : NSObject
@property (nonatomic, strong) NSString *property;
@end
「@property」相当于一个宏定义标签,在使用编译上述代码时,系统会对这个变量做三件事:生成实例变量 _property
、生成 getter
方法 - property
、生成 setter
方法 - setProperty:
。
@implementation DCObject {
NSString *_property;
}
- (NSString *)property {
return _property;
}
- (void)setProperty:(NSString *)property {
_property = property;
}
@end
@property 其实有元编程的思想,它能够为我们自动生成实例变量以及存取方法,而这三者构成了属性这个类似于语法糖的概念,为我们提供了更便利的点语法来访问属性:
self.property <=> [self property]
self.property = value <=> [self setProperty:value]
但是,在分类中因为类的实例变量的布局已经固定,使用 @property
已经无法向固定的布局中添加新的实例变量(这样做可能会覆盖子类的实例变量)。
如果我们在定义的分类中加一个属性,那么在使用这个属性的时候就会报警告。如:
@interface UIViewController (Transition)
@property (nonatomic, strong) MATransition *transition;
@end
Property 'transition' requires method 'setTransition:' to be defined - use @dynamic or provide a method implementation in this category.
Property 'transition' requires method 'transition' to be defined - use @dynamic or provide a method implementation in this category.
该warnning提示 categoryProperty
属性的存取方法需要手动去实现,或者以@dynamic
在运行时实现这些方法。即,分类中的 @property
编译时,并没有为我们生成实例变量以及存取方法,而需要我们手动实现。
下面使用关联对象的两个方法,来模拟构成属性的三个要素,就可以解决上述问题:
@implementation UIViewController (Transition)
- (MATransition *)transition {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setTransition:(MATransition *)transition {
objc_setAssociatedObject(self, @selector(transition), transition, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
- 用
objc_getAssociatedObject
和objc_setAssociatedObject
两个方法,来模拟『属性』的存取,即,将变量transition与UIViewController实例关联在一起;_cmd
代指当前方法的选择子,也即@selector(categoryProperty)
;- OBJC_ASSOCIATION_RETAIN_NONATOMIC是objc_AssociationPolicy类型值,相当于属性修饰符nonatomic、assign...等。
网友评论