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. js中的forEach

    chrome和firefox支持数组的forEach,但不支持对象的forEach,IE啥都不支持 jquery中的$.each(ArrayOrObject,function)既可以遍历数组又可以遍历 ...

  2. WPS Office Pro 2016 专业版

    感觉WPS还是不错的,Office安装包太大了.嘻嘻 政府专用正版序列号激活码,可永久有效激活! THUV2-32HH7-6NMHN-PTX7Y-QQCTH WPS Office Pro 2016 专 ...

  3. URL参数GB2312和UTF-8编码 自动识别

    网上找的,以备后用. 直接上代码: public static string QueryStringDecode(string key) { HttpRequest Request = System. ...

  4. Java设计模式(七) 模板模式

    [模板模式]在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 1,定义模板类 package com.pattern ...

  5. CodeForces 450B 矩阵

    A - Jzzhu and Sequences Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & ...

  6. Placemat:快速生成占位图片器

    快速的生成一张指定大小的图片 最简单的用法就是使用以下三个网址: https://placem.at/peoplehttps://placem.at/placeshttps://placem.at/t ...

  7. python面试2

    Python语言特性 1 Python的函数参数传递 看两个例子:     1 2 3 4 5 a = 1 def fun(a):     a = 2 fun(a) print a  # 1 1 2 ...

  8. 控件(选择类): ListBox, RadioButton, CheckBox, ToggleSwitch

    1.ListBox 的示例Controls/SelectionControl/ListBoxDemo.xaml <Page x:Class="Windows10.Controls.Se ...

  9. dede使用方法---如何调用指定栏目

    使用dede的时候,我们需要调用某一个指定的栏目,这个时候我们该如何使用标签呢?? 真相就是----{dede:type typeid='27'}*******{/dede:type} 完整的标签代码 ...

  10. xml解析工具-jdom

    前言:近期接触SSH框架的时候,经常得配置一下xml文件:今天闲来没事就挖挖xml解析的原理供大伙儿分享.本文主要通过一个简单的例子解析一个xml文件.明白其中缘由之后,大家想定义自己的xml也绝非难 ...