一、分类(category):
1.1 概念:
分类是OC中特有的语法,他标识一个指向分类的结构体的指针。使用分类可以在不进行子类化的情况下,为已经存在的类增加功能。原则上它只能增加方法,不能增加成员变量。
1.2 作用:
(1) 扩展替他人定义的类(即使你无法访问它们的源代码);
(2) 代替子类
(3) 将新类的实现代码分发给多个源文件
注意:
- 分类中添加“方法”,不能增加成员变量,因为分类的结构体指针中,没有属性列表,只有方法列表;
如果分类中声明了一个属性,那么,那么分类指挥生成这个属性的set、get方法声明,不会有实现(调用set方法给属性赋值,调用get方法获取属性值都会崩溃)
原则上分类只能添加方法,不能添加属性即成员变量,实际上可以通过getter、setter(即运行时)添加属性- 分类中可以写@property,但不会生成setter/getter方法,也不会生成实现以及是有的成员变量;
- 分类中可以访问原来类中的成员变量,但是只能访问
@protect
和@public
形式的变量。如果想要访问本类中的私有变量,分类和子类一样,只能通过方法来访问;- 如果分类中有和原有类同名的方法,会优先调用分类中的方法, 就是说会忽略原有类的方法。所以同名方法调用的优先级为分类 > 本类 > 父类。
- 如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。
1.3 通过运行时添加属性
由于OC是动态语言,方法真正的实现是通过runtime完成的,虽然系统不给我们生成setter/getter,但我们可以通过runtime手动添加setter/getter方法。
#import <objc/runtime.h>
static NSString *nameWithSetterGetterKey = @"nameWithSetterGetterKey";//定义一个key值
@implementation Programmer (Category)
//运行时实现setter方法
- (void)setNameWithSetterGetter:(NSString*)nameWithSetterGetter
{
objc_setAssociatedObject(self, &nameWithSetterGetterKey, nameWithSetterGetter, OBJC_ASSOCIATION_COPY);
}
//运行时实现getter方法
- (NSString*)nameWithSetterGetter
{
return objc_getAssociatedObject(self, &nameWithSetterGetterKey);
}
@end
注意:
以上代码仅仅是手动实现了setter/getter方法,但调用_成员变量依然报错。
二、扩展
2.1 概念
Extension是Category的一个特例。类扩展与分类相比只少了分类的名称,所以称之为“匿名分类”。
2.2 作用
(1) 能为某个类附加额外的属性,成员变量,方法声明;
(2) 一般的类扩展写到.m文件中;
(3) 一般的私有属性写到类扩展,外界不能访问;
三、继承
3.1 概念
继承是指一个新类拥有被继承类(父类)的全部属性和方法。子类与父类耦合度很高。当子类中需要有自己独特的行为,不想使用父类的方法,可以把父类的方法覆盖掉:直接在子类中用一样的名字写个方法。不用在.h中写,因为父类已经声明过了,直接在.m中重写。
3.2 作用
OC是单继承:一个类只能继承一个直接父类;
继承的好处:代码重用;
继承的缺点:父类的改变影响所有的子类。
四、category、extension和inheritance的区别
分类(category) | 延展(extension) | 继承(inheritance) | |
---|---|---|---|
功能 | 为类添加方法,不用知道类的源码,添加变量(通过运行时) | 为类添加私有变量和私有方法,在类的源文件中书写,所以知道类的源代码 | 即能为类添加方法又能添加变量 |
特点 | 添加的方法称为类的一部分,可以被子类继承 | 添加的变量和方法只有这个类内部访问,正常情况下外边不能访问(可以通过运行时),不能被子类继承 | 新添加的变量和方法只能子类才能具有,父类不具有 |
使用 | 使用原始类的对象(调用-方法)或者类(调用+方法)调用方法 | 在类内部(源文件)使用 | 只能子类使用 |