跳到主要内容

关联对象

问题

关联对象的原理是什么?有哪些使用场景?

答案

为什么需要关联对象

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_ASSIGNassign / unsafe_unretained
OBJC_ASSOCIATION_RETAIN_NONATOMICstrong, nonatomic
OBJC_ASSOCIATION_COPY_NONATOMICcopy, nonatomic
OBJC_ASSOCIATION_RETAINstrong, atomic
OBJC_ASSOCIATION_COPYcopy, 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 唯一性,更简洁)

相关链接