category类别借助Runtime添加属性

2018-03-22  本文已影响30人  Jey

回顾下类别和类扩展

  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#>)

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

上一篇下一篇

猜你喜欢

热点阅读