iOS动态性:动态添加属性的方法——关联(e.g. 向Category添加属性)
想到要如何为所有的对象增加实例变量吗?我们知道,使用Category可以很方便地为现有的类增加方法,但却无法直接增加实例变量。不过从Mac OS X v10.6开始,系统提供了Associative References,这个问题就很容易解决了。这种方法也就是所谓的关联(association),我们可以在runtime期间动态地添加任意多的属性,并且随时读取。所用到的两个重要runtime API是:
|
1
|
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) |
|
1
2
|
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1); |
现在我们结合一个实际的例子来说明他们的用法。假设我们现在打算利用category对UILabel进行属性补充,添加FlashColor属性。一般我们有个原则:能用category扩展就不用继承,因为随着继承深度的增加,代码的可维护性也会增加很多。使用category可以这么做:
|
1
2
3
4
5
6
7
8
|
#import <UIKit/UIKit.h>#import <objc/runtime.h>@interface UILabel (Associate)//单单从头文件看是不是很像一个类?再看看.m文件你就知道这些都是假象了- (nonatomic, retain) UIColor *FlashColor;@end |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#import "UILabel+Associate.h"@implementation UILabel (Associate)<br><br>@dynamic FlashColor;static char flashColorKey;- (void) setFlashColor:(UIColor *) flashColor{ objc_setAssociatedObject(self, &flashColorKey, flashColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (UIColor *) getFlashColor{ return objc_getAssociatedObject(self, &flashColorKey);}@end |
上面的例子有几个需要注意的地方:
1、key:我们注意到在函数签名中key的类型const void *,这表示key仅仅是一个地址,而不是字符串的内容,这也是为说明flashColorKey没有初始化的原因,因为具体指向什么内容我们无所谓,我们要的仅仅是地址!如果在setAssocaitedObject中你传入的是flashColorKey,那get方法得到的值将会是nil。正确的应该是传入地址&flashColorKey。
2、policy:这里的policy跟属性声明中的retain、assign、copy是一样的,不再赘述
3、在implement开始处的@dynamic声明。一般来说@dynamic与@synthesize都可以用来声明属性,@synthesize是默认的声明,意思是编译器在编译阶段自动为你的属性生成setter与getter;而@dynamic则告诉编译器,别慌,小子,编译阶段不用为我生成setter与getter,在runtime我已经自己实现了setter与getter。此处我们选择@dynamic。事实上,二者曾引起stackOverFlow上强烈的争论:请点这里。
下面我们再来看另一个例子,来源于APPLE GUIDE:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
#import <Foundation/Foundation.h>#import <objc/runtime.h> int main (int argc, const char * argv[]) { @autoreleasepool { /*Seciton 0. 关联数据的Key和Value*/ static char overviewKey; static const char *myOwnKey = "VideoProperty\0"; static const char intValueKey = 'i'; NSArray *array = [[NSArray alloc] initWithObjects:@ "One", @"Two", @"Three", nil]; // For the purposes of illustration, use initWithFormat: to ensure // we get a deallocatable string NSString *overview = [[NSString alloc] initWithFormat:@"%@", @"First three numbers"]; NSString *videoKeyValue = @"This is a video"; NSNumber *intValue = [[NSNumber alloc]initWithInt:5]; /*Section 1. 关联数据设置部分*/ objc_setAssociatedObject ( array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN ); [overview release]; objc_setAssociatedObject ( array, myOwnKey, videoKeyValue, OBJC_ASSOCIATION_RETAIN ); objc_setAssociatedObject ( array, &intValueKey, intValue, OBJC_ASSOCIATION_RETAIN ); /*Section 3. 关联数据查询部分*/ NSString *associatedObject = (NSString *) objc_getAssociatedObject (array, &overviewKey); NSLog(@"associatedObject: %@", associatedObject); NSString *associatedObject2 = (NSString *) objc_getAssociatedObject(array, myOwnKey); NSLog(@"Video Key value is %@", associatedObject2); NSString *assObject3 = (NSString *) objc_getAssociatedObject(array, &myOwnKey); if( assObject3 ) { NSLog(@"不会进入这里! assObject3 应当为nil!"); } else { NSLog(@"OK. 通过myOwnKey的地址是得不到数据的!"); } NSNumber *assKeyValue = (NSNumber *) objc_getAssociatedObject(array, &intValueKey); NSLog(@"Int value is %d",[assKeyValue intValue]); /*Section 3. 关联数据清理部分*/ objc_setAssociatedObject ( array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN ); objc_setAssociatedObject ( array, myOwnKey, nil, OBJC_ASSOCIATION_ASSIGN ); objc_setAssociatedObject ( array, &intValueKey, nil, OBJC_ASSOCIATION_ASSIGN ); [array release]; } return 0;} |
编程小翁@博客园,谢谢 前辈资料.
iOS动态性:动态添加属性的方法——关联(e.g. 向Category添加属性)的更多相关文章
- 【原】iOS动态性(一):动态添加属性的方法——关联(e.g. 向Category添加属性)
想到要如何为所有的对象增加实例变量吗?我们知道,使用Category可以很方便地为现有的类增加方法,但却无法直接增加实例变量.不过从Mac OS X v10.6开始,系统提供了Associative ...
- Python属性、方法和类管理系列之----__slots__属性
一句话说明 __slots__是用来限制实例的属性的,__slots__可以规定实例是否应该有__dict__属性:__slots__不能限制类的属性. 只有__slots__列表内的这些变量名可赋值 ...
- iOS Category 添加属性实现原理 - 关联对象
iOS Category 添加属性实现原理 - 关联对象 RunTime为Category动态关联对象 使用RunTime给系统的类添加属性,首先需要了解对象与属性的关系.对象一开始初始化的时候其属性 ...
- prototype为对象添加属性和方法
可以通过prototype来为已经定义好的的"类"添加属性和方法.这里来了解一下prototype的基础知识.prototype是"构造函数"的属性,不是实例的 ...
- C#动态引用DLL的方法
C#编程中,使用dll调用是经常的事,这样做的好处是非常多的,比如把某些功能封装到一个dll中,然后主程序动态调用这个dll. 废话不多说,举例说明如下. 首先,我们需要封装一个dll,vs2008下 ...
- Javascript 面向对象(共有方法,私有方法,特权方法,静态属性和方法,静态类)示例讲解
一,私有属性和方法 私有方法:私有方法本身是可以访问类内部的所有属性(即私有属性和公有属性),但是私有方法是不可以在类的外部被调用. <script> /* * 私有方法:私有方法本身是可 ...
- ScriptManager的几个属性和方法
ScriptManager的几个属性和方法 一.EnablePageMethods ScriptManager的EnablePageMethods属性用于设定客户端javascript直接调用服务 ...
- JavaScript:如何获得 Private、Privileged、Public 和 Static 成员(属性和方法)【翻译+整理】
本文内容 背景 把我们的对象放在一起 添加一个私有(Private)的属性 添加一个特权(Privileged)的方法 添加一个公共(Public)的属性和方法 添加一个静态(Static)的属性 我 ...
- 《前端之路》- TypeScript (四) class 中各类属性、方法,抽象类、多态
目录 一.TypeScript 中的类 二.TypeScript 中类的继承 三.TypeScript 中公共,私有与受保护的修饰符 3-1.属性的 public 3-2.属性的 private 3- ...
随机推荐
- JAVA提高十四:HashSet深入分析
前面我们介绍了HashMap,Hashtable,那么还有一个hash家族,那就是HashSet;在讲解HashSet前,大家先要知道的是HashSet是单值集合的接口,即是Collection下面的 ...
- c++用指针交换数组
对于指针一直很迷,今天看了一下指针交换数组,知识量很少,希望能帮助到大家. 利用指针来交换数组主要是为了节省时间嘛,有两种交换方式 第一种是写一个函数把数组传过去然后用swap交换,即可 代码如下: ...
- Adobe阅读器漏洞(adobe_cooltype_sing)学习研究
实验环境:Kali 2.0+Windows XP sp3+Adobe Reader 9.0.0 类别:缓冲区溢出 描述:这个漏洞针对Adobe阅读器9.3.4之前的版本,一个名为SING表对象中一个名 ...
- PHP启动:动态库加载失败(PHP Warning: PHP Startup: Unable to load dynamic library '/usr/local/php7/lib/php/extensions/no-debug-non-zts-20151012/*.so')
今天在linux上面智障一般搞了好久,本来想安装个swoole的,然后用 php -m 的命令想看下安装的PHP扩展库,发现有的扩展库有的可以出来,有的加载失败, 加载失败的错误类型: PHP Wa ...
- c语言的数组
1. 数组的基本概念 一个int类型的变量能保存一个人的年龄,如果想保存整个班的年龄呢? 1. 什么是数组 数组,从字面上看,就是一组数据的意思,没错,数组就是用来存储一组数据的 2. 数组的特点 ● ...
- 洛谷 P3379 【模板】最近公共祖先(LCA)Tarjan离线
题目链接:LCA tarjan离线 这道题目WA无数发,最后还是参考了大神的blog 谁会想到因为一个输入外挂WA呢 大概是我的挂是假挂吧...orz(其实加上外挂,速度提升很多) 用链式前向星保存边 ...
- ACM HDU 1081 To The Max
To The Max Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...
- spfa_dfs找负环
luogu #include<iostream> #include<cstdio> #include<cstring> #include<vector> ...
- Oracle的导入导出 DMP 文件
普通 导入: 将数据库完全导入,用户名userName 密码PassWord导入文件位置 E:\work\dmp\xxxxx.dmp (注意:导入的用户必须要跟导出时候的用户一致) imp userN ...
- 闲来无事研究一下酷狗缓存文件kgtemp的加密方式
此贴为本人原创,转载请注明出处 序 前几天更新了被打入冷宫很久的酷狗,等进入之后就感觉菊花一紧----试 听 居 然 都 要 开 通 音 乐 包(高品和无损)才行了,WTF! 这意味着以前缓存的都听不 ...