【原】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进行属性补充,可以这么做:

#import <UIKit/UIKit.h>
#import <objc/runtime.h>

@interface UILabel (Associate)

- (void) setFlashColor:(UIColor *) flashColor;

- (UIColor *) getFlashColor;

@end
#import "UILabel+Associate.h"

@implementation UILabel (Associate)

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是一样的,不再赘述

下面我们再来看另一个例子,来源于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;
}

  

时间: 2024-08-01 15:43:13

【原】iOS中动态添加属性的方法——关联(e.g. 向Category添加成员变量)的相关文章

iOS动态性:动态添加属性的方法——关联(e.g. 向Category添加属性)

想到要如何为所有的对象增加实例变量吗?我们知道,使用Category可以很方便地为现有的类增加方法,但却无法直接增加实例变量.不过从Mac OS X v10.6开始,系统提供了Associative References,这个问题就很容易解决了.这种方法也就是所谓的关联(association),我们可以在runtime期间动态地添加任意多的属性,并且随时读取.所用到的两个重要runtime API是: 1 OBJC_EXPORT void objc_setAssociatedObject(id

iOS中UIPickerView常见属性和方法的总结

UIPickerView是iOS中的原生选择器控件,使用方便,用法简单,效果漂亮. @property(nonatomic,assign) id<UIPickerViewDataSource> dataSource; @property(nonatomic,assign) id<UIPickerViewDelegate>   delegate; 设置数据源和代理 @property(nonatomic) BOOL showsSelectionIndicator; 是否显示选择框,在

JS内置对象的原型不能重定义?只能动态添加属性或方法?

昨天马上就快下班了,坐在我对面的同事突然问我一个问题,我说“爱过”,哈哈,开个玩笑.情况是这样的,他发现JS的内置对象的原型好像不能通过字面量对象的形式进行覆盖, 只能动态的为内置对象的原型添加属性或方法,下面那个具体的例子说明: var arr=[]; Array.prototype={ push:function(){ alert("1"); } }; arr.push(); //没有任何输出 有人可能会说了“你先定义的arr,后来又修改了Array.prototype,这时Arr

iOS 运行时添加属性和方法

原文链接http://blog.csdn.net/meegomeego/article/details/18356169第一种:runtime.h里的方法 BOOL class_addProperty(Class cls,constchar*name,constobjc_property_attribute_t*attributes,unsignedint attributeCount) #include <objc/runtime.h> #import <Foundation/Foun

Python-动态添加属性和方法

class Person(): Country='CN' def __init__(self,nm) self.nm=nm 动态添加实例属性及实例方法: p=Person() p.age=18 #直接赋值,动态添加实例属性 def set_age(self,age) #定义带self变量的函数 self.age=age def set_nm(self,nm) #定义带self变量的函数 self.nm=nm from types import MethodType p.set_age=Metho

prototype为对象添加属性和方法

可以通过prototype来为已经定义好的的"类"添加属性和方法.这里来了解一下prototype的基础知识.prototype是"构造函数"的属性,不是实例的属性. 示例: function HiClass() { this.sayHi = function(){ alert("hi"); } } var obj = new HiClass(); alert(HiClass.prototype);//outputs [object, objec

【JavaScript】浅析JavaScript对象如何添加属性和方法

向JavaScript类中添加属性和方法,最直观的做法就是在类中定义属性和方法.JavaScript是一门弱语言,除了直接定义还可以用prototype来添加. 下面介绍从外部向JavaScript添加属性和方法的四种方法,首先定义一个类 function MyClass(){} 1,使用类名添加属性 MyClass.prototype.myname="吴兴国01"; 2,使用类名添加方法 MyClass.prototype.myfunc=function(){alert("

JS中如何实现属性和方法的继承

JS中面向对象的实现: function Person(name,color){ this.name = name; this.color = color; } Person.prototype.showName = function(){ alert(this.name); } Person.prototype.showColor = function(){ alert(this.color); } function Worker(name,color,job,age){ Person.app

Yii2 文本框前加图标 input 添加属性的方法

<?= $form->field($model, 'username', [ 'inputTemplate' => '<div class="input-group"><span class="input-group-addon">@</span>{input}</div>', ])?> 添加属性的方法(注意inputOptions的使用): <?= $form->field($mo