面试题答案
一键面试关联对象的实现
在Objective-C运行时,关联对象是通过objc_setAssociatedObject
和objc_getAssociatedObject
等函数来实现的。运行时系统在对象的结构体中维护了一个额外的AssociationsManager
和AssociationsHashMap
来管理关联对象。当给一个对象设置关联对象时,会将对象的指针作为key,关联对象的信息(包括关联策略等)作为value存储在AssociationsHashMap
中。
底层数据结构
- AssociationsManager:这是一个管理类,它维护了一个线程安全的
AssociationsHashMap
。 - AssociationsHashMap:是一个哈希表,以对象指针作为key,以
ObjectAssociationMap
作为value。 - ObjectAssociationMap:也是一个哈希表,以关联对象的key(通常是一个
NSString
对象)作为key,以ObjcAssociation
作为value。 - ObjcAssociation:这个结构体存储了关联对象和关联策略。
相关函数的作用
- objc_setAssociatedObject:用于设置关联对象,它接收三个参数:目标对象、关联的key、关联的对象以及关联策略。例如:
NSString *key = @"myKey";
NSString *value = @"myValue";
objc_setAssociatedObject(self, (__bridge const void *)(key), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- objc_getAssociatedObject:用于获取关联对象,接收目标对象和关联的key作为参数。例如:
NSString *key = @"myKey";
NSString *value = objc_getAssociatedObject(self, (__bridge const void *)(key));
- objc_removeAssociatedObjects:用于移除对象所有的关联对象。
实际开发中的应用场景
- 给分类添加属性:在Objective-C中,分类不能直接添加实例变量,但可以通过关联对象来实现类似的效果。比如,给
UIButton
分类添加一个自定义的属性:
@interface UIButton (CustomProperty)
@property (nonatomic, strong) NSString *customTitle;
@end
@implementation UIButton (CustomProperty)
- (void)setCustomTitle:(NSString *)customTitle {
objc_setAssociatedObject(self, @selector(customTitle), customTitle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)customTitle {
return objc_getAssociatedObject(self, @selector(customTitle));
}
@end
- 为视图添加额外数据:在处理视图时,有时候需要给视图添加一些额外的数据,而不需要在视图类中定义属性。例如,在一个复杂的视图层级中,为某个
UIView
添加一个唯一标识:
UIView *myView = [[UIView alloc] init];
NSString *uniqueID = @"12345";
objc_setAssociatedObject(myView, @"uniqueID", uniqueID, OBJC_ASSOCIATION_COPY_NONATOMIC);
在后续处理中可以通过objc_getAssociatedObject
获取这个唯一标识进行相关操作。