【原】iOS动态性(一):动态添加属性的方法——关联(e.g. 向Category添加属性)
想到要如何为所有的对象增加实例变量吗?我们知道,使用Category可以很方便地为现有的类增加方法,但却无法直接增加实例变量。不过从Mac OS X v10.6开始,系统提供了Associative References,这个问题就很容易解决了。这种方法也就是所谓的关联(association),我们可以在runtime期间动态地添加任意多的属性,并且随时读取。所用到的两个重要runtime API是:
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);
现在我们结合一个实际的例子来说明他们的用法。假设我们现在打算利用category对UILabel进行属性补充,添加FlashColor属性。一般我们有个原则:能用category扩展就不用继承,因为随着继承深度的增加,代码的可维护性也会增加很多。使用category可以这么做:
#import <UIKit/UIKit.h>
#import <objc/runtime.h> @interface UILabel (Associate)//单单从头文件看是不是很像一个类?再看看.m文件你就知道这些都是假象了 - (nonatomic, retain) UIColor *FlashColor; @end
#import "UILabel+Associate.h" @implementation UILabel (Associate) @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:
#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;
}
=======================================================
原创文章,转载请注明 编程小翁@博客园,邮件zilin_weng@163.com,欢迎各位与我在C/C++/Objective-C/机器视觉等领域展开交流!
=======================================================
【原】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直接调用服务 ...
- python类属性和类方法(类的结构、实例属性、静态方法)
类属性和类方法 目标 类的结构 类属性和实例属性 类方法和静态方法 01. 类的结构 1.1 术语 —— 实例 使用面相对象开发,第 1 步 是设计 类 使用 类名() 创建对象,创建对象 的动作有两 ...
- JavaScript:如何获得 Private、Privileged、Public 和 Static 成员(属性和方法)【翻译+整理】
本文内容 背景 把我们的对象放在一起 添加一个私有(Private)的属性 添加一个特权(Privileged)的方法 添加一个公共(Public)的属性和方法 添加一个静态(Static)的属性 我 ...
随机推荐
- css3 keyframes在yuicompressor下压缩问题
@keyframes proBackAction { 0% { opacity:; } 100% { opacity: .8; } } @keyframes proBackAction { 0{ op ...
- Go Go
Go Go *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important ...
- 【转载】Grunt常用插件介绍
项目名称 grunt-contrib v0.8.0 项目地址 https://github.com/gruntjs/grunt-contrib 项目介绍 此项目是对grunt常用插件的集合,刚接触gr ...
- 红黑树(四)之 C++的实现
概要 前面分别介绍红黑树的理论知识和红黑树的C语言实现.本章是红黑树的C++实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章. 目录1. 红黑树的介绍2. 红黑树的C++ ...
- SharePoint 2013 搜索爬网功能
最近在政府部门介绍SharePoint 2013 新功能,我也准备了很多,比如SharePoint 2013的Search.以后有机会谈谈Office Web App,Workflow等. Share ...
- IEE分月表改造
IEE版本:5.1.40 需求:由于目前的IEE版本并不支持分区表,且删除历史数据效率很低,删除部分数据后空间释放方面也不理想. 现采用按月分表存放数据.这样卸载历史数据时,直接删除历史表即可. 改造 ...
- Android学习笔记之SoftReference软引用...
PS:其实这一篇和上一篇很类似,都是为了解决内存不足(OOM)这种情况的发生... 学习内容: 1.对象的引用类.... 最近也是通过项目中知道了一些东西,涉及到了对象的引用类,对象的引用类分为多 ...
- 《深入理解Java集合框架》系列文章
Introduction 关于C++标准模板库(Standard Template Library, STL)的书籍和资料有很多,关于Java集合框架(Java Collections Framewo ...
- mysql根据身份证信息来获取用户属性信息
需要:根据身份证信息来获取用户属性 方法:可以使用如下sql语句: ) ' then '北京市' ' then '天津市' ' then '河北省' ' then '山西省' ' then '内蒙古自 ...
- CSS布局 -- 左侧定宽,右侧自适应
左侧定宽,右侧自适应 有很多种方法可以实现 缩小窗口试试看? 方案一: 左边左浮动,右边加个margin-left 查看 demo <!DOCTYPE html PUBLIC "-// ...