区别 | Category | Extension |
---|---|---|
添加成员变量 | 不可以 | 可以 |
添加属性 | 不可以(但通过runtime可以) | 可以 |
添加方法 | 可以 | 可以 |
语法格式 | @interface NSObject (category) @end @implementation NSObject(category) @end //注意:括号里有名字 |
@interface ClassName () @end @implementation ClassName() @end //注意:括号里无名字; |
注意:
1、Extension通常定义在主类.m文件中,Extension中声明的方法直接在主类的.m文件中实现。
写在.h文件里,属性、方法公有;
写在.m文件里,属性、方法私有。
2、Extension只声明方法,不实现方法,会报警告:Method definition for '方法名' not found
3、为什么要用Category?
当你已经封装好一个完整的类库,随着需求的变化,你发现需要给类库中某个类的增加新方法,为了防止误调用引起不必要的麻烦,可以通过增加这个类的分类达到同样的效果,方便管理。
4、Extension是Category的一种特殊形式。
5、有时候面试官会问,runtime设置关联对象和不设置关联对象对增加属性有什么影响?
设置关联对象就是重写getter/setter方法;不设置关联对象,访问属性会报错,找不到getter/setter方法。(说白了就是Category添加属性的时候不会自动生成getter/setter方法,需要runtime设置关联对象来重写getter/setter方法)
Category里声明属性,不会自动生成带下划线的成员变量以及getter/setter方法,需要手动添加get/setter方法,通过runtime关联对象绑定,访问不会报错。
Extension是编译时自动生成带下划线的getter/setter方法。
利用Category通过runtime给Dog类添加属性:
Dog+Category.h
#import "Dog.h"
@interface Dog (Category)
@property (nonatomic, copy) NSString *sex;
@end
Dog+Category.m
#import "Dog+Category.h"
#import <objc/runtime.h>
static const void *SexKey = &SexKey;
@implementation Dog (Category)
- (NSString *)sex {
return objc_getAssociatedObject(self, SexKey);
}
- (void)setSex:(NSString *)sex {
objc_setAssociatedObject(self, SexKey, sex, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
@end
在分类里使用@property声明属性,只是将该属性添加到该类的属性列表,并声明了setter和getter方法,但是没有生成相应的成员变量,也没有实现setter和getter方法。所以说分类不能添加属性。但是在分类里使用@property声明属性后,又实现了setter和getter方法,那么在这个类以外可以正常通过点语法给该属性赋值和取值。就是说,在分类里使用@property声明属性,又实现了setter和getter方法后,可以认为给这个类添加上了属性。
一句话总结:Category添加属性不会自动生成带下划线的成员变量和setter/getter方法
参考资料:
https://www.jianshu.com/p/935142af6a47
https://blog.csdn.net/u012946824/article/details/51799664
欢迎指正拍砖!!!