iOS - 关联对象

详细总结 Objective-C 的关联对象功能:

1. 基本使用

objectivec 复制代码
// 1. 设置关联对象
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);

// 2. 获取关联对象
id objc_getAssociatedObject(id object, const void *key);

// 3. 移除关联对象
objc_removeAssociatedObjects(id object);

2. 关联策略

objectivec 复制代码
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           // 弱引用
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 强引用,非原子
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   // 复制,非原子
    OBJC_ASSOCIATION_RETAIN = 01401,       // 强引用,原子
    OBJC_ASSOCIATION_COPY = 01403          // 复制,原子
};

3. 实现示例

3.1 分类中添加属性

objectivec 复制代码
// UIView+Extension.h
@interface UIView (Extension)
@property (nonatomic, strong) NSString *identifier;
@end

// UIView+Extension.m
@implementation UIView (Extension)

static void *IdentifierKey = &IdentifierKey;

- (void)setIdentifier:(NSString *)identifier {
    objc_setAssociatedObject(self, 
                            IdentifierKey, 
                            identifier, 
                            OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)identifier {
    return objc_getAssociatedObject(self, IdentifierKey);
}

@end

3.2 使用宏简化

objectivec 复制代码
// 定义关联属性的宏
#define OBJC_ASSOCIATION_PROPERTY_STRONG(_getter_, _setter_, _association_) \
- (void)_setter_:(id)object { \
    objc_setAssociatedObject(self, @selector(_getter_), object, _association_); \
} \
- (id)_getter_ { \
    return objc_getAssociatedObject(self, @selector(_getter_)); \
}

// 使用宏
@implementation UIView (Extension)
OBJC_ASSOCIATION_PROPERTY_STRONG(identifier, setIdentifier, OBJC_ASSOCIATION_COPY_NONATOMIC)
@end

4. 关键点

4.1 Key 的选择

objectivec 复制代码
// 1. 静态变量地址
static char kAssociatedObjectKey;
objc_setAssociatedObject(obj, &kAssociatedObjectKey, value, policy);

// 2. 选择器
objc_setAssociatedObject(obj, @selector(propertyName), value, policy);

// 3. 字符串常量
static NSString *const kAssociatedKey = @"kAssociatedKey";
objc_setAssociatedObject(obj, (__bridge void *)kAssociatedKey, value, policy);

4.2 内存管理

objectivec 复制代码
// 强引用示例
objc_setAssociatedObject(self, 
                        @selector(strongProperty), 
                        object, 
                        OBJC_ASSOCIATION_RETAIN_NONATOMIC);

// 弱引用示例
objc_setAssociatedObject(self, 
                        @selector(weakProperty), 
                        object, 
                        OBJC_ASSOCIATION_ASSIGN);

5. 线程安全

objectivec 复制代码
// 原子操作
objc_setAssociatedObject(self, 
                        key, 
                        value, 
                        OBJC_ASSOCIATION_RETAIN); // 使用带原子性的关联策略

// 手动加锁
@synchronized(self) {
    objc_setAssociatedObject(self, 
                            key, 
                            value, 
                            OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

6. 最佳实践

6.1 属性封装

objectivec 复制代码
@interface NSObject (Associated)

@property (nonatomic, strong) id associatedObject;
@property (nonatomic, weak) id weakAssociatedObject;
@property (nonatomic, copy) NSString *copyAssociatedObject;

@end

6.2 清理处理

objectivec 复制代码
- (void)dealloc {
    // 移除特定关联对象
    objc_setAssociatedObject(self, @selector(associatedObject), nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    // 或移除所有关联对象
    objc_removeAssociatedObjects(self);
}

7. 注意事项

objectivec 复制代码
// 1. 避免循环引用
@implementation MyClass
- (void)setupBlock {
    __weak typeof(self) weakSelf = self;
    self.associatedBlock = ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        [strongSelf doSomething];
    };
}

// 2. 合理选择关联策略
- (void)setDelegate:(id<MyDelegate>)delegate {
    objc_setAssociatedObject(self, 
                            @selector(delegate), 
                            delegate, 
                            OBJC_ASSOCIATION_ASSIGN); // 代理使用 ASSIGN
}

关联对象的优点:

  1. 无需修改原类即可添加属性
  2. 支持各种属性特性(strong/weak/copy)
  3. 线程安全选项
  4. 运行时动态性

注意事项:

  1. 合理使用关联策略
  2. 注意内存管理
  3. 避免过度使用
  4. 考虑性能影响
  5. 注意命名冲突
相关推荐
茶底世界之下7 小时前
斜光下的旧自行车:用 Awaking 留一版复古胶片色
ios·app·产品
2501_9160088910 小时前
iPhone 设备信息查看,用 KeyMob 看型号、序列号、电池健康和 UDID
android·ios·小程序·https·uni-app·iphone·webview
茶底世界之下1 天前
iPhone Duo 适配实战,Awaking 踩过的 8 个坑
ios·swiftui·swift
跨境数据猎手1 天前
HTTP 响应体编码与压缩:识别、解码
网络协议·http·ios
也非非也1 天前
iPhone 中国区 AI 落地:Apple 与阿里千问合作的技术观察
大数据·人工智能·ios·agent·iphone·智子
茶底世界之下1 天前
同一片泳池,清透还是奶油胶片?用 Awaking 做两版成片
ios
2501_916008891 天前
iOS App 图标、启动屏和多语言搭配 方法,上架前使用KXBuild一次做好 App 图标
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
沐梯子1 天前
MOSS-Transcribe-Diarize 和豆包语音识别哪个好?多人会议录音转写的准确率与说话人归属对比
人工智能·语音识别·xcode
2501_915918411 天前
iOS 推送通知怎么实现,从 APNs p8 密钥到 iOS 真机收到第一条推送
vscode·ios·objective-c·个人开发·swift·敏捷流程
茶底世界之下2 天前
雨夜街角裁成方图,人物与冷暖光还能共存吗?
ios