美文网首页
category类别借助Runtime添加属性

category类别借助Runtime添加属性

作者: Jey | 来源:发表于2018-03-22 10:58 被阅读30次

    回顾下类别和类扩展

    1. 类别的作用
          category 可以在不修改原来类的基础上,为一个类扩展方法。只能添加,不能删除修改,并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,类别具有更高的优先级
    2. 类扩展
          category和extensions的不同在于后者可以添加属性。另外后者添加的方法是必须要实现的,不然会出现警告,可以认为是一个私有的Category。

    类别与类扩展的区别:

    ①类别中原则上只能增加方法,在一个类中用@property声明属性,编译器会自动帮我们生成成员变量和setter/getter,但分类的指针结构体中,根本没有属性列表。所以在分类中用@property声明属性,既无法生成成员变量也无法生成setter/getter,不能直接声明属性。
    ②类扩展不仅可以增加方法,还可以增加实例变量(或者属性),该实例变量默认是@private类型的,范围只能在自身类。
    ③类扩展中声明的方法没被实现,编译器会报警,但是类别中的方法没被实现编译器是不会有任何警告的。这是因为类扩展是在编译阶段被添加到类中,而类别是在运行时添加到类中。
    ④类扩展不能像类别那样拥有独立的实现部分(@implementation部分),也就是说,类扩展所声明的方法必须依托对应类的实现部分来实现。

    既然上述所说的第一点已经说了不能生产setter/getter方法,那怎么才能为类别添加属性呢?由于OC是动态语言,方法最后的实现都是通过runtime完成的,虽然系统不给我们生成setter/getter,但我们可以通过runtime手动添加setter/getter方法,接下来上代码:

    代码如下:

    // People类
    import <Foundation/Foundation.h>
    
    @interface People : NSObject
    
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) NSString *gender;
    
    @end
    

    // 分类

    #import "People.h"
    
    @interface People (P)
    
    - (NSString *)address;
    - (void)setAddress:(NSString *)address;
    
    @end
    
    #import "People+P.h"
    #import <objc/runtime.h>
    
    @implementation People (P)
    
    - (NSString *)address
    {
        return objc_getAssociatedObject(self, _cmd);
    }
    
    - (void)setAddress:(NSString *)address
    {
        objc_setAssociatedObject(self,
                                 @selector(address),
                                 address,
                                 OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    @end
    

    // 实现

    People *model = [[People alloc] init];
    model.name = @"迪丽热巴";
    model.gender = @"女";
    model.address = @"sz市xxxxx";
        
    NSLog(@"%@-%@-%@",model.name, model.gender, model.address);
    

    关键代码

    /**
         关联
         @param object#> 对象
         @param key#> 关键字
         @param value#> 关联的对象
         @param policy#> 关联策略
         */
        objc_setAssociatedObject(<#id object#>,
                                 <#const void *key#>,
                                 <#id value#>,
                                 <#objc_AssociationPolicy policy#>)
    
    /**
         获取关联对象
    
         @param object#> 被关联对象
         @param key#> 关键字(属性)
         */
        objc_getAssociatedObject(<#id object#>, <#const void *key#>)
    

    看到这里,面试的时候千万别再这么肯定的回答分类中不能添加属性了。

    相关文章

      网友评论

          本文标题:category类别借助Runtime添加属性

          本文链接:https://www.haomeiwen.com/subject/yhaoqftx.html