runtime(二) 给对象、分类添加实例变量

本文介绍如何使用Objective-C的关联对象功能为类实例动态添加变量。通过示例演示了如何为NSString实例添加NSDate类型的变量,并解释了不同存储策略及其对应@property属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在开发中有时候想给对象实例添加个变量来存储数据,但又无法直接声明,比如说既有类的分类。这个时候我们就可以通过 关联对象 在运行时给对象关联一个 对象 来存储数据。(注意:并不是真实的添加了一个实例变量)

关联对象 可以给某个对象关联其他对象并用key来区分其他对象。需要注意的是,存储对象的时候要指明 存储策略,用来维护对象的内存管理语义。存储策略是 objc_AssociationPolicy 枚举定义,以下是存储策略对应的 @property属性:

存储策略类型对应的@property属性
OBJC_ASSOCIATION_ASSIGNweak
OBJC_ASSOCIATION_RETAIN_NONATOMICstrong, nonatomic
OBJC_ASSOCIATION_COPY_NONATOMICcopy, nonatomic
OBJC_ASSOCIATION_RETAINstrong
OBJC_ASSOCIATION_COPYcopy

用下面的方法可以管理关联对象:

// 这个方法可以根据指定策略给对象关联对象值
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)
复制代码

对于关联对象这个OC特性,我们可以把对象想象成一个 NSDictionary,关联对象需要一个 key( 类型是 opaque pointer,无类型的指针 ) 来区分,我们可以把要添加的变量名作为 key ,把变量的值作为关联的对象来存储到 ”对象“ 这个 NSDictionary 中。 所以,关联对象的

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
复制代码

方法类似于字典的 [dict setObject: forKey:] 方法。

在存储和获取关联对象时需要用一个相等的 key ,因为是给 Class 的实例对象关联对象,所以一般用静态变量来做 key

说的再多,不如上段代码!

比如说,我们给 NSString 实例加上个 NSDate 类型的 date 变量。什么?给字符串加个日期变量是要干袅?我要给字符串过个生日不行吗! 别闹,举个栗子嘛!(捂脸逃跑~~~)

首先,我们先给 NSString 新建个名为 RT 的 category。 在头文件中有个 NSDate 类型的 date 属性:

//  NSString+RT.h
//  runtime
#import <Foundation/Foundation.h>
//
@interface NSString (RT)
//
@property (nonatomic, strong) NSDate *date;
//
@end
复制代码

在分类中的属性只会生成 getset 方法,并不会生成变量。 所以我们需要重写 getset 方法,关联对象以变相实现添加变量,在现实文件中:

//  NSString+RT.m
//  runtime
#import <objc/runtime.h>
#import "NSString+RT.h"
//
@implementation NSString (RT)
//
static void *runtime_date_key = "date";
- (NSDate *)date{
    return objc_getAssociatedObject(self, runtime_date_key);
}
//
- (void)setDate:(NSDate *)date{
    objc_setAssociatedObject(self, runtime_date_key, date, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end
复制代码

需要注意的是,关联对象用到的 key 是个无类型的指针,一般来说是静态来修饰。 另外,给对象关联的只能是对象,如果是 intfloat 等类型需要 NSNumber 进行包装。 因为 date 是强引用和非原子属性,所以关联策略用 OBJC_ASSOCIATION_RETAIN_NONATOMIC

然后执行代码:

NSString *string = @"runtimeTestString";
string.date = [NSDate date];
NSLog(@"string.date = %@",string.date);
复制代码

输出结果:

2016-04-12 21:27:31.099 runtime[2837:103727] string.date = 2016-04-12 13:27:31 +0000
复制代码

注意:

  • 定义关联对象时需要指定内存管理语义,用来模拟对象对变量的拥有关系
  • 尽量避免使用关联对象,因为如果出现bug不易于问题排查

我的博客:iosgg.cn/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值