iOS Runtime详解之给Category添加成员变量
2016-01-18 16:08
519 查看
好吧,没办法,在项目中我想用category,至于为什么用category而不用继承,这个我在这就不多说了,我的category博客中特意讲过,在这里就不赘述,我用了category,但是想要给我这个类增加几个属性(成员变量),思来想去,往上说用runtime,可是自己都没用过,感觉好高大上,自己都不敢直视,可是没办法,必须得直视,好吧,看了看官方文档,在网上又看了些资料,最后还是入了Runtime的门,在这里跟大家分享一下,下边是一个demo截图:
由图中我们可以看到,有一个PbPlatMainController,增加了一个category,名字叫PbPlatModulMgrImpl,然后里边有几个属性叫registerDict,optionalModule...
以为category是无法增加成员变量(属性)的,所以说我利用了Runtime
思想介绍:
关联对象类似于成员变量,不过是在运行时添加的。我们通常会把成员变量(Ivar)放在类声明的头文件中,或者放在类实现的@implementation后面。但这有一个缺点,我们不能在分类中添加成员变量。如果我们尝试在分类中添加新的成员变量,编译器会报错。
我们可能希望通过使用(甚至是滥用)全局变量来解决这个问题。但这些都不是Ivar,因为他们不会连接到一个单独的实例。因此,这种方法很少使用。
Objective-C针对这一问题,提供了一个解决方案:即关联对象(Associated Object)。
我们可以把关联对象想象成一个Objective-C对象(如字典),这个对象通过给定的key连接到类的一个实例上。不过由于使用的是C接口,所以key是一个void指针(const void *)。我们还需要指定一个内存管理策略,以告诉Runtime如何管理这个对象的内存。这个内存管理的策略可以由以下值指定:
当宿主对象被释放时,会根据指定的内存管理策略来处理关联对象。如果指定的策略是assign,则宿主释放时,关联对象不会被释放;而如果指定的是retain或者是copy,则宿主释放时,关联对象会被释放。我们甚至可以选择是否是自动retain/copy。当我们需要在多个线程中处理访问关联对象的多线程代码时,这就非常有用了。
我们将一个对象连接到其它对象所需要做的就是下面两行代码:
在这种情况下,self对象将获取一个新的关联的对象anObject,且内存管理策略是自动retain关联对象,当self对象释放时,会自动release关联对象。另外,如果我们使用同一个key来关联另外一个对象时,也会自动释放之前关联的对象,这种情况下,先前的关联对象会被妥善地处理掉,并且新的对象会使用它的内存。
我们可以使用objc_removeAssociatedObjects函数来移除一个关联对象,或者使用objc_setAssociatedObject函数将key指定的关联对象设置为nil。
详细代码如下:
#import "PbPlatMainController+PbPlatModulMgrImpl.h"
#import <objc/runtime.h>
static const void *registerDictKey = ®isterDictKey;
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中是不需要导入的
由图中我们可以看到,有一个PbPlatMainController,增加了一个category,名字叫PbPlatModulMgrImpl,然后里边有几个属性叫registerDict,optionalModule...
以为category是无法增加成员变量(属性)的,所以说我利用了Runtime
思想介绍:
关联对象(Associated Object)
关联对象是Runtime中一个非常实用的特性,不过可能很容易被忽视。关联对象类似于成员变量,不过是在运行时添加的。我们通常会把成员变量(Ivar)放在类声明的头文件中,或者放在类实现的@implementation后面。但这有一个缺点,我们不能在分类中添加成员变量。如果我们尝试在分类中添加新的成员变量,编译器会报错。
我们可能希望通过使用(甚至是滥用)全局变量来解决这个问题。但这些都不是Ivar,因为他们不会连接到一个单独的实例。因此,这种方法很少使用。
Objective-C针对这一问题,提供了一个解决方案:即关联对象(Associated Object)。
我们可以把关联对象想象成一个Objective-C对象(如字典),这个对象通过给定的key连接到类的一个实例上。不过由于使用的是C接口,所以key是一个void指针(const void *)。我们还需要指定一个内存管理策略,以告诉Runtime如何管理这个对象的内存。这个内存管理的策略可以由以下值指定:
我们将一个对象连接到其它对象所需要做的就是下面两行代码:
详细代码如下:
#import "PbPlatMainController+PbPlatModulMgrImpl.h"
#import <objc/runtime.h>
static const void *registerDictKey = ®isterDictKey;
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中是不需要导入的
相关文章推荐
- iOS 一种自定义颜色的方法
- iOS x-www-form-urlencoded格式传参
- iOS 调试
- ios设备信息
- iOS CAReplicatorLayer简单笔记
- iOS截屏
- iOS空页面 DZNEmptyDataSet
- ios crash 日志分析
- iOS开发~CocoaPods使用详细说明
- IOS模拟动态图 大图和小图动态切换
- IOS-学习笔记(1)
- iOS9 提示框的使用
- IOS UserDefaults简介(一)
- iOS内存管理之@property属性详解
- iOS-内测-蒲公英应用内测使用
- 《ios与os x多线程和内存管理》
- ios 简单绘制
- iOS 多语言版本的开发
- 如何处理iOS中照片的方向
- ios耗时操作