继承
继承是指一个新类拥有被继承类(父类)的全部属性和方法。例如,只有继承NSObject,才有创建对象的能力。NSObject是大部分类的基类(根类,root class)。
当A类继承B类时,A就拥有了B的所有成员变量(属性)和方法,这也是继承的主要目的。
继承的优点:代码重用。继承的缺点:父类的改变影响子类。
子类可以重写父类的方法,将父类的方法覆盖掉,直接在子类中用同一个名字写一个方法,不用在.h文件中说声明,直接在.m中重写即可。
如果重写父类的方法,但是还想使用父类的功能,则在重新方法中可使用super来调用父类的方法。
继承体系中方法的调用顺序是
- 在自己类中找
- 如果没有再去父类中找
- 如果父类中没有则去父类的父类中找,一直找到基类。
OC中类方法也是可以继承的,也是可以重写的。类方法和实例方法可以重名,但是子类中不能定义和父类中同名的成员变量。
OC是单继承:一个类只能继承一个直接父类
OC是多层继承:B可以继承A,C可以继承B,则C也继承A。
分类
分类(类别)的作用:扩展已有类的功能。
- 为原来的类增加方法。
- 在方法内部可以访问原有类的成员变量,但这些成员变量一定要定义在头文件中。
Category
Category 是表示一个指向分类的结构体的指针,其定义如下:
typedef struct objc_category *Category;
struct objc_category {
char *category_name OBJC2_UNAVAILABLE; // 分类名
char *class_name OBJC2_UNAVAILABLE; // 分类所属的类名
struct objc_method_list *instance_methods OBJC2_UNAVAILABLE; // 实例方法列表
struct objc_method_list *class_methods OBJC2_UNAVAILABLE; // 类方法列表
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 分类所实现的协议列表
//通过上面我们可以发现,这个结构体主要包含了分类定义的实例方法与类方法,
//其中instance_methods 列表是 objc_class 中方法列表的一个子集,
//而class_methods列表是元类方法列表的一个子集。
//但这个结构体里面根本没有属性列表,
}
分类原则上是不能添加属性的。但@property可以编译通过,只是无法生成setter和getter方法,但只要调用属性,就会报错。
由于OC是动态语言,方法真正的实现是通过runtime完成的,虽然系统不给我们生成setter/getter,但我们可以通过runtime手动添加setter/getter方法。
扩展
Extension是Category的一个特例。类扩展与分类相比只少了分类的名称,所以称之为“匿名分类”。
@interface XXX ()
//私有属性
//私有方法(如果不实现,编译时会报警,Method definition for 'XXX' not found)
@end
为一个类添加额外的原来没有变量,方法和属性
一般的类扩展写到.m文件中
一般的私有属性写到.m文件中的类扩展中
分类和扩展的区别
- 类别中原则上只能增加方法
- 类扩展不仅可以增加方法,还可以增加实例变量(或者属性),只是该实例变量默认是@private类型的(用范围只能在自身类,而不是子类或其他地方);
- 类扩展中声明的方法没被实现,编译器会报警,但是类别中的方法没被实现编译器是会有任何警告的。这是因为类扩展是在编译阶段被添加到类中,而类别是在运行时添加到类中。
- 类扩展不能像类别那样拥有独立的实现部分(@implementation部分),也就是说,类扩展所声明的方法必须依托对应类的实现部分来实现。
- 定义在 .m 文件中的类扩展方法为私有的,定义在 .h 文件(头文件)中的类扩展方法为公有的。类扩展是在 .m 文件中声明私有方法的非常好的方式。