关联对象
问题
关联对象的原理是什么?有哪些使用场景?
答案
为什么需要关联对象
Category 不能添加实例变量(类结构在编译时已确定)。关联对象允许在运行时给任意对象附加数据。
使用
#import <objc/runtime.h>
@interface UIView (Badge)
@property (nonatomic, strong) UILabel *badgeLabel;
@end
@implementation UIView (Badge)
static const void *kBadgeLabelKey = &kBadgeLabelKey;
- (void)setBadgeLabel:(UILabel *)badgeLabel {
objc_setAssociatedObject(self, kBadgeLabelKey, badgeLabel,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UILabel *)badgeLabel {
return objc_getAssociatedObject(self, kBadgeLabelKey);
}
@end
关联策略
| 策略 | 对应属性 |
|---|---|
OBJC_ASSOCIATION_ASSIGN | assign / unsafe_unretained |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | strong, nonatomic |
OBJC_ASSOCIATION_COPY_NONATOMIC | copy, nonatomic |
OBJC_ASSOCIATION_RETAIN | strong, atomic |
OBJC_ASSOCIATION_COPY | copy, atomic |
底层原理
全局 AssociationsManager
└── AssociationsHashMap
└── key: 被关联对象地址
└── ObjectAssociationMap
└── key: 关联 key
└── value: ObjcAssociation(策略 + 值)
关联对象存储在全局哈希表中,不影响原始对象的内存布局。对象 dealloc 时,Runtime 自动清理其所有关联对象。
常见面试问题
Q1: 关联对象会导致内存泄漏吗?
答案:不会。对象销毁时 dealloc → _object_remove_assocations() 会自动清理所有关联对象。但如果关联策略选错(如 ASSIGN 导致野指针),可能引发崩溃。
Q2: 关联对象的 key 用什么?
答案:任何唯一地址都行。常见方式:
static const void *key = &key;(指向自身地址,唯一)@selector(propertyName)(利用 SEL 唯一性,更简洁)