回顾下类别和类扩展
- 类别的作用
category 可以在不修改原来类的基础上,为一个类扩展方法。只能添加,不能删除修改,并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,类别具有更高的优先级 - 类扩展
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#>)
看到这里,面试的时候千万别再这么肯定的回答分类中不能添加属性了。
网友评论