iOS @Property属性之动态添加

runtime 实现

首先要引入 <objc/runtime.h>,需要利用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:",
)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容