iOS @Property属性之动态添加

runtime 实现

首先要引入 ,需要利用runtime.h文件的两个函数完成

第一步:添加属性参数

  • class_addProperty方法

    /** 
    * Adds a property to a class.
    * 
    * 
    * @param cls 修改的类
    * @param name 属性名字
    * @param attributes 属性数组
    * @param attributeCount 属性数组数量
    * 
    * @return \c YES if the property was added successfully, otherwise \c NO
    *  (for example, the class already has that property).
    */
    OBJC_EXPORT BOOL
    class_addProperty(Class _Nullable cls, const char * _Nonnull name,
                const objc_property_attribute_t * _Nullable attributes,
                unsigned int attributeCount)OBJC_AVAILABLE(10.7, 4.3, 9.0, 1.0, 2.0);
    

下面开始添加:

    objc_property_attribute_t type = { "T", "@\"NSString\"" };//T:类型
    objc_property_attribute_t ownership = { "C", "" }; // C:copy
    objc_property_attribute_t nonatomic = { "N", "" }; // N:nonatomic
    objc_property_attribute_t backingivar  = { "V", "_name" };//V: 实例变量
    objc_property_attribute_t attributs[] = { type, ownership,nonatomic, backingivar };
    class_addProperty([self class], "name", attributs, 4);


       //下面是输出添加的成员变量
       unsigned int count;
       objc_property_t *propertyList = class_copyPropertyList([self class], &count);
       for (unsigned int i = 0; i< count; i++)
       {
           const char *name = property_getName(propertyList[i]);
           NSLog(@"__%@",[NSString stringWithUTF8String:name]);
           objc_property_t property = propertyList[i];
           const char *a = property_getAttributes(property);
           NSLog(@"属性信息__%@",[NSString stringWithUTF8String:a]);
       }

输出结果如下:

    __name
    属性信息__T@"NSString",C,N,V_name

上面可以看出,只用class_addProperty只添加了一个成员变量,想要object.name的话还得需要setter方法和getter方法的。你以为添加完一个属性就调用上面那个方法就能添加出所有的东西来吗,还记得之前讲过的@Property的实质吗

    @Property = Ivar + Setter + Getter

第二步:添加setter和getter方法

  • class_addMethod方法

    /** 
     * Adds a new method to a class with a given name and implementation.
     * 
     * @param cls The class to which to add a method.//添加方法名字
     * @param name A selector that specifies the name of the method being added.//方法名称
     * @param imp A function which is the implementation of the new method. The function must take at least two arguments—self and _cmd.//方法的实现必须至少2个参数,self 和 _cmd
     * @param types An array of characters that describe the types of the arguments to the method. //描述
     * 
     * @return YES if the method was added successfully, otherwise NO   //y成功,n失败
     *  (for example, the class already contains a method implementation with that name).
     *
     * @note class_addMethod will add an override of a superclass's implementation, //会覆盖superclass 的实现;
     *  but will not replace an existing implementation in this class.       //已经存在的不会替换
     *  To change an existing implementation, use method_setImplementation.//想要改变,使用method_setImplementation方法
     */
     OBJC_EXPORT BOOL
     class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, 
              const char * _Nullable types) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
    

下面开始添加setter/getter方法:

   if(class_addMethod([self class],NSSelectorFromString(@"name"), (IMP)nameGetter, "@@:")){
       NSLog(@"name get 方法添加成功");
   }else{
       NSLog(@"myName get 方法添加失败");
   }

   if(class_addMethod([self class],NSSelectorFromString(@"setName:"), (IMP)nameSetter, "v@:@")){
       NSLog(@"name set 方法添加成功");
   }else{
       NSLog(@"name set 方法添加失败");
   }
    //这一行是必须要添加的,否则不会调用自定义的setter和getter方法
    [self setValue:propertyValue forKey:propertyName];

//需要在@implementation内定义setter和getter

//class_getInstanceVariable   获取类中指定名称实例成员变量的信息
NSString *nameGetter(id self, SEL _cmd) {
    Ivar ivar = class_getInstanceVariable([self class], "_name");
    return object_getIvar(self, ivar);
}
void nameSetter(id self, SEL _cmd, NSString *newName) {
    Ivar ivar = class_getInstanceVariable([self class], "_name");
    id oldName = object_getIvar(self, ivar);
    if (oldName != newName) object_setIvar(self, ivar, [newName copy]);
}

结果输出如下:

name get 方法添加成功
name set 方法添加成功
__name
属性信息__T@"NSString",C,N,V_name
方法列表:   (
"name",
"setName:",
)

你可能感兴趣的:(iOS @Property属性之动态添加)