http://blog.csdn.net/shengyumojian/article/details/44919695

在ios运行过程中,有几种方式能够动态的添加属性。

1-通过runtime动态关联对象

主要用到了objc_setAssociatedObject,objc_getAssociatedObject以及objc_removeAssociatedObjects

  1. //在目标target上添加关联对象,属性名propertyname(也能用来添加block),值value
  2. + (void)addAssociatedWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
  3. id property = objc_getAssociatedObject(target, &propertyName);
  4. if(property == nil)
  5. {
  6. property = value;
  7. objc_setAssociatedObject(target, &propertyName, property, OBJC_ASSOCIATION_RETAIN);
  8. }
  9. }
  10. //获取目标target的指定关联对象值
  11. + (id)getAssociatedValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
  12. id property = objc_getAssociatedObject(target, &propertyName);
  13. return property;
  14. }

优点:这种方式能够使我们快速的在一个已有的class内部添加一个动态属性或block块。

缺点:不能像遍历属性一样的遍历我们所有关联对象,且不能移除制定的关联对象,只能通过removeAssociatedObjects方法移除所有关联对象。

2-通过runtime动态添加Ivar

主要用到objc_allocateClassPair,class_addIvar,objc_registerClassPair

  1. //在目标target上添加属性(已经存在的类不支持,可跳进去看注释),属性名propertyname,值value
  2. + (void)addIvarWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
  3. if (class_addIvar([target class], [propertyName UTF8String], sizeof(id), log2(sizeof(id)), "@")) {
  4. YYLog(@"创建属性Ivar成功");
  5. }
  6. }
  7. //获取目标target的指定属性值
  8. + (id)getIvarValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
  9. Ivar ivar = class_getInstanceVariable([target class], [propertyName UTF8String]);
  10. if (ivar) {
  11. id value = object_getIvar(target, ivar);
  12. return value;
  13. } else {
  14. return nil;
  15. }
  16. }

优点:动态添加Ivar我们能够通过遍历Ivar得到我们所添加的属性。

缺点:不能在已存在的class中添加Ivar,所有说必须通过objc_allocateClassPair动态创建一个class,才能调用class_addIvar创建Ivar,最后通过objc_registerClassPair注册class。

3-通过runtime动态添加property

主要用到class_addProperty,class_addMethod,class_replaceProperty,class_getInstanceVariable

  1. //在目标target上添加属性,属性名propertyname,值value
  2. + (void)addPropertyWithtarget:(id)target withPropertyName:(NSString *)propertyName withValue:(id)value {
  3. //先判断有没有这个属性,没有就添加,有就直接赋值
  4. Ivar ivar = class_getInstanceVariable([target class], [[NSString stringWithFormat:@"_%@", propertyName] UTF8String]);
  5. if (ivar) {
  6. return;
  7. }
  8. /*
  9. objc_property_attribute_t type = { "T", "@\"NSString\"" };
  10. objc_property_attribute_t ownership = { "C", "" }; // C = copy
  11. objc_property_attribute_t backingivar  = { "V", "_privateName" };
  12. objc_property_attribute_t attrs[] = { type, ownership, backingivar };
  13. class_addProperty([SomeClass class], "name", attrs, 3);
  14. */
  15. //objc_property_attribute_t所代表的意思可以调用getPropertyNameList打印,大概就能猜出
  16. objc_property_attribute_t type = { "T", [[NSString stringWithFormat:@"@\"%@\"",NSStringFromClass([value class])] UTF8String] };
  17. objc_property_attribute_t ownership = { "&", "N" };
  18. objc_property_attribute_t backingivar  = { "V", [[NSString stringWithFormat:@"_%@", propertyName] UTF8String] };
  19. objc_property_attribute_t attrs[] = { type, ownership, backingivar };
  20. if (class_addProperty([target class], [propertyName UTF8String], attrs, 3)) {
  21. //添加get和set方法
  22. class_addMethod([target class], NSSelectorFromString(propertyName), (IMP)getter, "@@:");
  23. class_addMethod([target class], NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]), (IMP)setter, "v@:@");
  24. //赋值
  25. [target setValue:value forKey:propertyName];
  26. NSLog(@"%@", [target valueForKey:propertyName]);
  27. YYLog(@"创建属性Property成功");
  28. } else {
  29. class_replaceProperty([target class], [propertyName UTF8String], attrs, 3);
  30. //添加get和set方法
  31. class_addMethod([target class], NSSelectorFromString(propertyName), (IMP)getter, "@@:");
  32. class_addMethod([target class], NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]), (IMP)setter, "v@:@");
  33. //赋值
  34. [target setValue:value forKey:propertyName];
  35. }
  36. }
  37. id getter(id self1, SEL _cmd1) {
  38. NSString *key = NSStringFromSelector(_cmd1);
  39. Ivar ivar = class_getInstanceVariable([self1 class], "_dictCustomerProperty");  //basicsViewController里面有个_dictCustomerProperty属性
  40. NSMutableDictionary *dictCustomerProperty = object_getIvar(self1, ivar);
  41. return [dictCustomerProperty objectForKey:key];
  42. }
  43. void setter(id self1, SEL _cmd1, id newValue) {
  44. //移除set
  45. NSString *key = [NSStringFromSelector(_cmd1) stringByReplacingCharactersInRange:NSMakeRange(0, 3) withString:@""];
  46. //首字母小写
  47. NSString *head = [key substringWithRange:NSMakeRange(0, 1)];
  48. head = [head lowercaseString];
  49. key = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:head];
  50. //移除后缀 ":"
  51. key = [key stringByReplacingCharactersInRange:NSMakeRange(key.length - 1, 1) withString:@""];
  52. Ivar ivar = class_getInstanceVariable([self1 class], "_dictCustomerProperty");  //basicsViewController里面有个_dictCustomerProperty属性
  53. NSMutableDictionary *dictCustomerProperty = object_getIvar(self1, ivar);
  54. if (!dictCustomerProperty) {
  55. dictCustomerProperty = [NSMutableDictionary dictionary];
  56. object_setIvar(self1, ivar, dictCustomerProperty);
  57. }
  58. [dictCustomerProperty setObject:newValue forKey:key];
  59. }
  60. + (id)getPropertyValueWithTarget:(id)target withPropertyName:(NSString *)propertyName {
  61. //先判断有没有这个属性,没有就添加,有就直接赋值
  62. Ivar ivar = class_getInstanceVariable([target class], [[NSString stringWithFormat:@"_%@", propertyName] UTF8String]);
  63. if (ivar) {
  64. return object_getIvar(target, ivar);
  65. }
  66. ivar = class_getInstanceVariable([target class], "_dictCustomerProperty");  //basicsViewController里面有个_dictCustomerProperty属性
  67. NSMutableDictionary *dict = object_getIvar(target, ivar);
  68. if (dict && [dict objectForKey:propertyName]) {
  69. return [dict objectForKey:propertyName];
  70. } else {
  71. return nil;
  72. }
  73. }

优点:这种方法能够在已有的类中添加property,且能够遍历到动态添加的属性。

缺点:比较麻烦,getter和setter需要自己写,且值也需要自己存储,如上面的代码,我是把setter中的值存储到了_dictCustomerProperty里面,在getter中再从_dictCustomerProperty读出值。

4-通过setValue:forUndefinedKey动态添加键值

这种方法优点类似property,需要重写setValue:forUndefinedKey和valueForUndefinedKey:,存值方式也一样,需要借助一个其它对象。由于这种方式没通过runtime,所以也比较容易理解。在此就不举例了。

ios动态添加属性的几种方法的更多相关文章

  1. Emit学习(3) - OpCodes - 动态添加属性、构造函数、方法

    上一篇介绍了 IL 的部分, 基础的部分, 暂时就介绍到那里了, 接下来要进入代码编写阶段了. 今天的主题是 在代码运行的过程中, 去动态的创建类, 属性, 方法. 来源:http://www.cnb ...

  2. 动态添加class的一种方法

    外面可以写一层class再用:class 绑定新的clss进去  而且可以用三目运算.爽歪歪

  3. 我的Python学习笔记(四):动态添加属性和方法

    一.动态语言与静态语言 1.1 动态语言 在运行时代码可以根据某些条件改变自身结构 可以在运行时引进新的函数.对象.甚至代码,可以删除已有的函数等其他结构上的变化 常见的动态语言:Object-C.C ...

  4. day_5.26python动态添加属性和方法

    python动态添加属性和方法 既然给类添加⽅法,是使⽤ 类名.⽅法名 = xxxx ,那么给对象添加⼀个⽅法 也是类似的 对象.⽅法名 = xxx '''2018-5-26 13:40:09pyth ...

  5. WPF编程,通过Double Animation动态更改控件属性的一种方法。

    原文:WPF编程,通过Double Animation动态更改控件属性的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/a ...

  6. WPF编程,通过【帧】动态更改控件属性的一种方法。

    原文:WPF编程,通过[帧]动态更改控件属性的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/detail ...

  7. js对象动态添加属性,方法

    1. 动态添加属性,方法 var object = new Object(); object.name = "name"; object.age = 19; >>> ...

  8. python 动态添加属性及方法及“__slots__的作用”

    1.动态添加属性 class Person(object): def __init__(self, newName, newAge): self.name = newName self.age = n ...

  9. python动态添加属性和方法

    ---恢复内容开始--- python动态添加属性: class Person(object): def __init__(self,newName,newAge): self.name = newN ...

随机推荐

  1. ASP.NET Web API 安全验证之摘要(Digest)认证

    在基本认证的方式中,主要的安全问题来自于用户信息的明文传输,而在摘要认证中,主要通过一些手段避免了此问题,大大增加了安全性. 1.客户端匿名的方式请求 (无认证) HTTP/ Unauthorized ...

  2. 转一篇Unity客户端与Java服务器的通信

    转自:http://www.programering.com/a/MTNxYDMwATQ.html A few days ago a friend asked me about Unity3D ins ...

  3. centos 服务器内存管理

    du su /目录/ 查看改目录大小 ls -lht /  查看文件详情,显示文件大小(直观) df -h 查看系统内存占用情况

  4. 转:PHP中防止SQL注入的方法

    [一.在服务器端配置] 安全,PHP代码编写是一方面,PHP的配置更是非常关键. 我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最 ...

  5. there is issue about change event of checkbox in the ie8 oe ie7

    some people said the change event of checkbox can not trigger in the ie7 or ie8,that's not true. thi ...

  6. Android获取屏幕宽度、高度的4种方法

    记录学习之用,有相同的问题可以参考 方法一: WindowManager wm = (WindowManager) this .getSystemService(Context.WINDOW_SERV ...

  7. 【BZOJ 4600】【SDOI 2016】硬币游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=4600 转化成nim游戏 因为对于每一个反面朝上的硬币编号可以拆成\(2^a3^bc\),选择这个硬币 ...

  8. Spring Security3学习实例

    Spring Security是什么? Spring Security,这是一种基于Spring AOP和Servlet过滤器的安全框架.它提供全面的安全性解决方案,同时在Web请求级和方法调用级处理 ...

  9. MVC3中使用RadioButtonFor()

    创建页面  进行初始化   默认 男 被选中 <div class="label"> <div class="editor-label"> ...

  10. 算法与数据结构之选择排序(C语言)

    #include<stdio.h> #include<stdlib.h> void SelectSort(int *a,int n);//预声明要调用的函数 int main( ...