Runtime的实践——给一个类添加属性(关联对象)

本文介绍了如何利用Objective-C的Runtime和Category给现有类添加属性,特别是通过关联对象实现这一目标。通过设置和获取关联对象的函数,可以在不修改原有类的情况下动态添加属性并赋值,解决了Category不能添加实例变量的问题。文中给出了具体的代码示例,并验证了添加属性的成功。

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

相关文章:
《Runtime的初步认识——结构体与类》
《Runtime的初步认识——消息机制》

一提到给一个类添加点什么,我们有可能首先就想到类别(Category)。那么我们就弄一下。

利用 Category 给现有的类添加属性

比如我们要给一个 NSArray 添加一个属性叫做NSString *name。

我们首先新建一个Objective-C文件。

File: Name

File Type:Category

Class:NSArray

然后我们在NSArray+Name.h里面写

@interface NSArray (Name)

@property (nonatomic, copy) NSString *name;

@end

于是我们就给NSArray这个类添加了一个NSString类型的name

现在我们导入NSArray+Name.h文件去实现一下代码验证一下

NSArray *array = [[NSArray alloc] init];

array.name = @"test";

NSLog(@"%@", array.name);

我们新建了一个NSArray,并把@"test"赋值给了array的属性中。

然后输出看看这个属性是否成功赋值。

于是你很开心地按下了command+R,发现这家伙奔溃了,奔溃原因:

[__NSArray0 setName:]: unrecognized selector sent to instance 0x100102f80

NSArray并没有这个setName:这个方法,仔细一看 Xcode 还给我们两个警告。

于是我们进入NSArray+Name.m文件写上 get 方法和 set 方法:

@implementation NSArray (Name)

- (void)setName:(NSString *)name {
    _name = name;
}


- (NSString *)name {
    return _name;
}
@end

很好,两个错误,因为并没有实例变量。或许你觉得可以添加一个扩展。于是你写了一个扩展并且给他添加了一个实例变量NSString *name,然后这次连编译都不通过。

于是你哭了/(ㄒoㄒ)/~~

Category只能给已有的类添加方法,不能添加实例变量

那现在怎么办呢?难道我们之前的问题就解决不了了?

这个时候runtime的作用就体现出来了。之前我们说过,它可以动态的去修改我们创建的结构体(也就已经声明的类)。

利用 Runtime 和 Category 给现有的类添加属性

关联对象

关联对象是只将一个对象a利用一个key绑定一个对象b,之后a就可以利用这个key获取到这个对象b

同时,a可以二次绑定同一个key,并且会替换之前被绑定的对象。之后再通过key获取对象,就是一个新绑定的值了。

是不是感觉和普通的属性很像?可以赋值,可以取值,可以重复赋值然后覆盖。

的确,只是调用一个函数而已。

函数

Runtime 给了我们两个函数来实现关联对象,你只需要#import <objc/runtime.h>就可以使用这两个函数了。

这两个函数分别是:

//set function
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);

//get function
id objc_getAssociatedObject(id object, const void *key);
赋值函数

来看看 set 函数里的东西

  • object 要持有“别的对象”的对象,这里也就是指a
  • key 关联关键字,是一个字符串常亮,是一个地址(这里注意,地址必须是不变的,地址不同但是内容相同的也不算同一个key)
  • value 也就是值,你可以猜的出应该是值b
  • policy 这是一个枚举,你可以点进去看看这个枚举是什么:
    • OBJC_ASSOCIATION_ASSIGN
    • OBJC_ASSOCIATION_RETAIN_NONATOMIC
    • OBJC_ASSOCIATION_COPY_NONATOMIC
    • OBJC_ASSOCIATION_RETAIN
    • OBJC_ASSOCIATION_COPY

如果你了解 Objective-C,那你一定知道上面这些枚举的作用了。

所以,我们就可以在前面的NSArray的分类里这么写

- (void)setName:(NSString *)name {
    objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
取值函数

现在来看看 get 函数里的东西

  • object 持有“别的对象”的对象,这里指a
  • key 关联关键字

看完 set 函数之后,get 函数就显而易见了!这里不用多解释,立马就可以写代码

- (NSString *)name {
    return objc_getAssociatedObject(self, "name");
}

验证结果

运行demo,成功输出如下内容:

2016-05-11 09:22:32.950 runtime+Category demo[923:36795] test
Program ended with exit code: 0

说明我们给 array 赋值的结果成功保留下来,下一次去取值可以成功取到上一次保存的值了。

推荐:
《Runtime的实践——方法交换》

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值