ios动态添加属性的几种方法
http://blog.csdn.net/shengyumojian/article/details/44919695
在ios运行过程中,有几种方式能够动态的添加属性。
1-通过runtime动态关联对象
主要用到了objc_setAssociatedObject,objc_getAssociatedObject以及objc_removeAssociatedObjects
- //在目标target上添加关联对象,属性名propertyname(也能用来添加block),值value
- + (void)addAssociatedWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
- id property = objc_getAssociatedObject(target, &propertyName);
- if(property == nil)
- {
- property = value;
- objc_setAssociatedObject(target, &propertyName, property, OBJC_ASSOCIATION_RETAIN);
- }
- }
- //获取目标target的指定关联对象值
- + (id)getAssociatedValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
- id property = objc_getAssociatedObject(target, &propertyName);
- return property;
- }
优点:这种方式能够使我们快速的在一个已有的class内部添加一个动态属性或block块。
缺点:不能像遍历属性一样的遍历我们所有关联对象,且不能移除制定的关联对象,只能通过removeAssociatedObjects方法移除所有关联对象。
2-通过runtime动态添加Ivar
主要用到objc_allocateClassPair,class_addIvar,objc_registerClassPair
- //在目标target上添加属性(已经存在的类不支持,可跳进去看注释),属性名propertyname,值value
- + (void)addIvarWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
- if (class_addIvar([target class], [propertyName UTF8String], sizeof(id), log2(sizeof(id)), "@")) {
- YYLog(@"创建属性Ivar成功");
- }
- }
- //获取目标target的指定属性值
- + (id)getIvarValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
- Ivar ivar = class_getInstanceVariable([target class], [propertyName UTF8String]);
- if (ivar) {
- id value = object_getIvar(target, ivar);
- return value;
- } else {
- return nil;
- }
- }
优点:动态添加Ivar我们能够通过遍历Ivar得到我们所添加的属性。
缺点:不能在已存在的class中添加Ivar,所有说必须通过objc_allocateClassPair动态创建一个class,才能调用class_addIvar创建Ivar,最后通过objc_registerClassPair注册class。
3-通过runtime动态添加property
主要用到class_addProperty,class_addMethod,class_replaceProperty,class_getInstanceVariable
- //在目标target上添加属性,属性名propertyname,值value
- + (void)addPropertyWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
- //先判断有没有这个属性,没有就添加,有就直接赋值
- Ivar ivar = class_getInstanceVariable([target class], [[NSString stringWithFormat:@"_%@", propertyName] UTF8String]);
- if (ivar) {
- return;
- }
- /*
- objc_property_attribute_t type = { "T", "@\"NSString\"" };
- objc_property_attribute_t ownership = { "C", "" }; // C = copy
- objc_property_attribute_t backingivar = { "V", "_privateName" };
- objc_property_attribute_t attrs[] = { type, ownership, backingivar };
- class_addProperty([SomeClass class], "name", attrs, 3);
- */
- //objc_property_attribute_t所代表的意思可以调用getPropertyNameList打印,大概就能猜出
- objc_property_attribute_t type = { "T", [[NSString stringWithFormat:@"@\"%@\"",NSStringFromClass([value class])] UTF8String] };
- objc_property_attribute_t ownership = { "&", "N" };
- objc_property_attribute_t backingivar = { "V", [[NSString stringWithFormat:@"_%@", propertyName] UTF8String] };
- objc_property_attribute_t attrs[] = { type, ownership, backingivar };
- if (class_addProperty([target class], [propertyName UTF8String], attrs, 3)) {
- //添加get和set方法
- class_addMethod([target class], NSSelectorFromString(propertyName), (IMP)getter, "@@:");
- class_addMethod([target class], NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]), (IMP)setter, "v@:@");
- //赋值
- [target setValue:value forKey:propertyName];
- NSLog(@"%@", [target valueForKey:propertyName]);
- YYLog(@"创建属性Property成功");
- } else {
- class_replaceProperty([target class], [propertyName UTF8String], attrs, 3);
- //添加get和set方法
- class_addMethod([target class], NSSelectorFromString(propertyName), (IMP)getter, "@@:");
- class_addMethod([target class], NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]), (IMP)setter, "v@:@");
- //赋值
- [target setValue:value forKey:propertyName];
- }
- }
- id getter(id self1, SEL _cmd1) {
- NSString *key = NSStringFromSelector(_cmd1);
- Ivar ivar = class_getInstanceVariable([self1 class], "_dictCustomerProperty"); //basicsViewController里面有个_dictCustomerProperty属性
- NSMutableDictionary *dictCustomerProperty = object_getIvar(self1, ivar);
- return [dictCustomerProperty objectForKey:key];
- }
- void setter(id self1, SEL _cmd1, id newValue) {
- //移除set
- NSString *key = [NSStringFromSelector(_cmd1) stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""];
- //首字母小写
- NSString *head = [key substringWithRange:NSMakeRange(0, 1)];
- head = [head lowercaseString];
- key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:head];
- //移除后缀 ":"
- key = [key stringByReplacingCharactersInRange:NSMakeRange(key.length - 1, 1) withString:@""];
- Ivar ivar = class_getInstanceVariable([self1 class], "_dictCustomerProperty"); //basicsViewController里面有个_dictCustomerProperty属性
- NSMutableDictionary *dictCustomerProperty = object_getIvar(self1, ivar);
- if (!dictCustomerProperty) {
- dictCustomerProperty = [NSMutableDictionary dictionary];
- object_setIvar(self1, ivar, dictCustomerProperty);
- }
- [dictCustomerProperty setObject:newValue forKey:key];
- }
- + (id)getPropertyValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
- //先判断有没有这个属性,没有就添加,有就直接赋值
- Ivar ivar = class_getInstanceVariable([target class], [[NSString stringWithFormat:@"_%@", propertyName] UTF8String]);
- if (ivar) {
- return object_getIvar(target, ivar);
- }
- ivar = class_getInstanceVariable([target class], "_dictCustomerProperty"); //basicsViewController里面有个_dictCustomerProperty属性
- NSMutableDictionary *dict = object_getIvar(target, ivar);
- if (dict && [dict objectForKey:propertyName]) {
- return [dict objectForKey:propertyName];
- } else {
- return nil;
- }
- }
优点:这种方法能够在已有的类中添加property,且能够遍历到动态添加的属性。
缺点:比较麻烦,getter和setter需要自己写,且值也需要自己存储,如上面的代码,我是把setter中的值存储到了_dictCustomerProperty里面,在getter中再从_dictCustomerProperty读出值。
4-通过setValue:forUndefinedKey动态添加键值
这种方法优点类似property,需要重写setValue:forUndefinedKey和valueForUndefinedKey:,存值方式也一样,需要借助一个其它对象。由于这种方式没通过runtime,所以也比较容易理解。在此就不举例了。
ios动态添加属性的几种方法的更多相关文章
- Emit学习(3) - OpCodes - 动态添加属性、构造函数、方法
上一篇介绍了 IL 的部分, 基础的部分, 暂时就介绍到那里了, 接下来要进入代码编写阶段了. 今天的主题是 在代码运行的过程中, 去动态的创建类, 属性, 方法. 来源:http://www.cnb ...
- 动态添加class的一种方法
外面可以写一层class再用:class 绑定新的clss进去 而且可以用三目运算.爽歪歪
- 我的Python学习笔记(四):动态添加属性和方法
一.动态语言与静态语言 1.1 动态语言 在运行时代码可以根据某些条件改变自身结构 可以在运行时引进新的函数.对象.甚至代码,可以删除已有的函数等其他结构上的变化 常见的动态语言:Object-C.C ...
- day_5.26python动态添加属性和方法
python动态添加属性和方法 既然给类添加⽅法,是使⽤ 类名.⽅法名 = xxxx ,那么给对象添加⼀个⽅法 也是类似的 对象.⽅法名 = xxx '''2018-5-26 13:40:09pyth ...
- WPF编程,通过Double Animation动态更改控件属性的一种方法。
原文:WPF编程,通过Double Animation动态更改控件属性的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/a ...
- WPF编程,通过【帧】动态更改控件属性的一种方法。
原文:WPF编程,通过[帧]动态更改控件属性的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/detail ...
- js对象动态添加属性,方法
1. 动态添加属性,方法 var object = new Object(); object.name = "name"; object.age = 19; >>> ...
- python 动态添加属性及方法及“__slots__的作用”
1.动态添加属性 class Person(object): def __init__(self, newName, newAge): self.name = newName self.age = n ...
- python动态添加属性和方法
---恢复内容开始--- python动态添加属性: class Person(object): def __init__(self,newName,newAge): self.name = newN ...
随机推荐
- NPOI2.0学习(二)
如果你要编辑的行和单元格,原本没有值,或者从未创建过的,就必须先创建. //在第二行创建行 IRow row = sheet.CreateRow(); //在第二行的第一列创建单元格 ICell ce ...
- 自定义getElementByClass
DOM已经实现了getElementByClass,这个功能内部是怎么实现的呢 js代码及如何使用: function getElementByClass(className,parentNode){ ...
- vijos-1003等价表达式
明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数表达式是和 ...
- 东大OJ-Prim算法
1222: Sweep the snow 时间限制: 1 Sec 内存限制: 128 MB 提交: 28 解决: 18 [提交][状态][讨论版] 题目描述 After the big big s ...
- 工作框架各种使用整理---使用Cache
<service verb="get" noun="Products"> <implements service="sang.pro ...
- 1020理解MySQL——索引与优化
转自http://www.cnblogs.com/hustcat/archive/2009/10/28/1591648.html 写在前面:索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性 ...
- Myeclipse下JSP打开报空指针异常解决方法。
Myeclipse下JSP打开报空指针异常解决方法 一.运行JSP文件就出错 静态的JSP页面访问时候正常,只要是牵涉到数据库的页面就出错,出错见下图. 出现这种情况让我调试了一天,各种断点,各种改代 ...
- Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property 'orderdetails' of 'class com.luchao.mybatis.first.po.Orders' with value 'Orderdetail [id=null, ordersId=3, itemsId=1, it
从上面异常的解释来看是因为反射不能将Orders设置到orderdetails属性上,仔细检查了MyBatis的配置文件,发现: <collection property="order ...
- eclipse-搭建maven的war项目集合spring注解方式
工具:eclipse 4.4.2 版本号:20150219-0600 jdk:1.7 1.下图创建maven工程,然后next 下图选择工程保存位置(这里选择默认),next 下图选择webapp项目 ...
- java-正则表达式过滤字符串中的html标签
案例 import java.util.regex.Matcher; import java.util.regex.Pattern; /** * <p> * Title: HTML相关的正 ...