iOS Runtime详解之给Category添加成员变量(怎么设置关联对象)

好吧,没办法,在项目中我想用category,至于为什么用category而不用继承,这个我在这就不多说了,我的category博客中特意讲过,在这里就不赘述,我用了category,但是想要给我这个类增加几个属性(成员变量),思来想去,往上说用runtime,可是自己都没用过,感觉好高大上,自己都不敢直视,可是没办法,必须得直视,好吧,看了看官方文档,在网上又看了些资料,最后还是入了Runtime的门,在这里跟大家分享一下,下边是一个demo截图:

由图中我们可以看到,有一个PbPlatMainController,增加了一个category,名字叫PbPlatModulMgrImpl,然后里边有几个属性叫registerDict,optionalModule...

以为category是无法增加成员变量(属性)的,所以说我利用了Runtime

思想介绍:

关联对象(Associated Object)

关联对象是Runtime中一个非常实用的特性,不过可能很容易被忽视。

关联对象类似于成员变量,不过是在运行时添加的。我们通常会把成员变量(Ivar)放在类声明的头文件中,或者放在类实现的@implementation后面。但这有一个缺点,我们不能在category中添加成员变量。如果我们尝试在category中添加新的成员变量,编译器会报错。

我们可能希望通过使用(甚至是滥用)全局变量来解决这个问题。但这些都不是Ivar,因为他们不会连接到一个单独的实例。因此,这种方法很少使用。

Objective-C针对这一问题,提供了一个解决方案:即关联对象(Associated Object)。

我们可以把关联对象想象成一个Objective-C对象(如字典),这个对象通过给定的key连接到类的一个实例上。设置关联对象中的值的键是个不透明的指针,如果在两个键上调用isEqual方法返回的值是YES,那么NSDictionary就认为两者相等,然而在设置关联对象值时,若想令两个键匹配到同一个值,则两者必须是完全相同的指针才可以,鉴于此,在设置关联对象值时,通常使用静态全局变量做键。不过由于使用的是C接口,所以key是一个void指针(const void *)。我们还需要指定一个内存管理策略,以告诉Runtime如何管理这个对象的内存。这个内存管理的策略可以由以下值指定:

1
2
3
4
5
OBJC_ASSOCIATION_ASSIGN
OBJC_ASSOCIATION_RETAIN_NONATOMIC
OBJC_ASSOCIATION_COPY_NONATOMIC
OBJC_ASSOCIATION_RETAIN
OBJC_ASSOCIATION_COPY

当宿主对象被释放时,会根据指定的内存管理策略来处理关联对象。如果指定的策略是assign,则宿主释放时,关联对象不会被释放;而如果指定的是retain或者是copy,则宿主释放时,关联对象会被释放。我们甚至可以选择是否是自动retain/copy。当我们需要在多个线程中处理访问关联对象的多线程代码时,这就非常有用了。

我们将一个对象连接到其它对象所需要做的就是下面两行代码:

1
2
3
static char myKey;
 
objc_setAssociatedObject(self, &myKey, anObject, OBJC_ASSOCIATION_RETAIN);

在这种情况下,self对象将获取一个新的关联的对象anObject,且内存管理策略是自动retain关联对象,当self对象释放时,会自动release关联对象。另外,如果我们使用同一个key来关联另外一个对象时,也会自动释放之前关联的对象,这种情况下,先前的关联对象会被妥善地处理掉,并且新的对象会使用它的内存。

1
id anObject = objc_getAssociatedObject(self, &myKey);

我们可以使用objc_removeAssociatedObjects函数来移除一个关联对象,或者使用objc_setAssociatedObject函数将key指定的关联对象设置为nil来移除一个关联对象。


详细代码如下:

#import "PbPlatMainController+PbPlatModulMgrImpl.h"
#import <objc/runtime.h>

static const void *registerDictKey = &registerDictKey;
static const void *optionalModuleKey = &optionalModuleKey;
static const void *upgradeModuleKey = &upgradeModuleKey;
static const void *informationModuleKey = &informationModuleKey;

@implementation PbPlatMainController (PbPlatModulMgrImpl)

@dynamic registerDict;
@dynamic upgradeModule;
@dynamic informationModule;
@dynamic optionalModule;

- (NSMutableDictionary *)registerDict {
    return objc_getAssociatedObject(self, registerDictKey);
}

- (void)setRegisterDict:(NSMutableDictionary *)registerDict {
    objc_setAssociatedObject(self, registerDictKey, registerDict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (PbOptionalModule *)optionalModule {
    return objc_getAssociatedObject(self, optionalModuleKey);
}

- (void)setOptionalModule:(PbOptionalModule *)optionalModule {
    objc_setAssociatedObject(self, optionalModuleKey, optionalModule, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (PbUpgradeModule *)upgradeModule {
    return  objc_getAssociatedObject(self, upgradeModuleKey);
}

- (void)setUpgradeModule:(PbUpgradeModule *)upgradeModule {
    objc_setAssociatedObject(self, upgradeModuleKey, upgradeModule, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

对,就是上边的code,先导入<objc/runtime.h>,swift中是不需要导入的



// 设置关联对象
void objc_setAssociatedObject ( id object, const void *key, id value, objc_AssociationPolicy policy );
 
// 获取关联对象
id objc_getAssociatedObject ( id object, const void *key );

warning:

这篇文章我们着重讲的是给category添加属性,不过还是不推荐这么给category添加属性,我们尽量把封装数据用的全部属性都定义在主接口里.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS Runtime是一种运行时环境,它是iOS操作系统中的重要组成部分。iOS Runtime为开发者提供了一套动态询问、修改和扩展应用程序行为的机制。 首先,iOS Runtime实现了Objective-C语言的动态特性。Objective-C是一种面向对象的编程语言,它具有动态特性,即在运行时能够动态地修改对象的行为。iOS Runtime允许开发者通过运行时系统对类、对象、方法以及属性进行动态操作。例如,开发者可以在运行时为某个类添加新的方法,也可以通过运行时修改类的实例变量。 其次,iOS Runtime还提供了消息发送机制。在Objective-C中,对象之间的通信是通过消息发送来完成的。iOS Runtime负责将消息转发给正确的接收者,并执行相应的方法。这个过程是动态的,开发者可以在运行时动态改变消息的接收者或方法的实现。这为Objective-C语言带来了很高的灵活性。 此外,iOS Runtime还支持方法的交换与替换。开发者可以通过运行时机制,在运行时将一个方法的实现替换为另一个方法的实现,或者交换两个方法的实现。这对于调试、性能监控和代码扩展都是非常有用的。 总结来说,iOS RuntimeiOS操作系统中实现Objective-C语言特性的核心组件。它提供了动态特性的支持,使开发者能够在运行时动态地修改类、对象和方法的行为,实现更加灵活和可扩展的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值