继承
我们说Objective-C也是一门面向对象的语言,因此也具有面向对象语言的基本特征.在Objective-C的继承体系中,位于最顶层的根类是NSObject,类比Java中的java.lang.Object类,我们定义的所有类都是它的子类。我们知道在Java中继承一个类需要extends关键字,在Objective-C中,继承一个类只需要一个冒号(:),语法如下:
继 承使得子类可以从父类中获得一些属性和已有方法。例如我们之前已经定义一个手机类(Phone),现在我们再来定义一个iPhone手机类 (IphonePhone)和Android手机类(AndroidPhone),都继承至手机类(Phone),在IphonePhone和 AndroidPhone中我们不写任何代码.
然后我们在main.m中实例化IphonePhone和AndroidPhone,我们发现我们可以访问定义在Phone中的变量和方法:
我 们在实例化IphonePhone时,IphonePhone* iphone = [[IphonePhone alloc] init]; alloc和init我们并没有定义,事实是alloc和init是NSObject中定义的方法,并且alloc是类方法,init是实例方法.
和 Java一样,Objective-C中每个子类只能有一个超类,也就是说ClassC不能同时继承ClassA和ClassB,这点和C++不一样.但 Objective-C允许多层继承,例如,ClassB继承ClassA,ClassC又继承ClassB,那么我们也说ClassC是ClassA的 子类.
到目前为止,当一个类需要引用另一个类,我们通使用 import 类名,例如在AndroidPhone.h和IphonePhone.h都继承至Phone,所以我们需要import Phone.h,有时候我们在一个类中引用另一个类,并不是为了继承,而ClassB是ClassA的一个属性.为了说明这个问题,我们把Phone中原 先的os属性抽象成一个类(OS),比如os也有版本名和版本号两个属性:
然后我们需要修改Phone.h中的代码:
我 们看第三行使用了@class指令,这是因为编译器在遇到定义的实例变量OS时,必须了解OS是什么.当然我们也可以使用#import “OS.h”代替这条指令.但是使用@class指令提高了效率.因为h文件在修改后,所有import该h文件的所有文件必须重新build,因此,如 果把#import写在h文件中,import该h文件的文件也就会产生不必要的编译.在这里,编译器不需要引入和处理整个OS.h文件,虽然它很小,只需要知道OS是一个类名. 但是如果我们需要使用一个类的方法(在实现部分),使用@class指令是不够的,因为编译器需要更多的消息.它需要清楚方法有多少参数,参数的类型,以 及方法的返回类型等.
二者的区别在于:
- import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
- 在 头文件中, 一般只需要知道被引用的类的名称就可以了。 不需要知道其内部的实体变量和方法,所以在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
- 在编译效率方 面考虑,如果你有100个头文件都#import了同一个头文件,或者这些文件是依次引用的,如A–>B, B–>C, C–>D这样的引用关系。当最开始的那个头文件有变化的话,后面所有引用它的类都需要重新编译,如果你的类有很多的话,这将耗费大量的时间。而是用 @class则不会。
- 如果有循环依赖关系,如:A–>B, B–>A这样的相互依赖关系,如果使用#import来相互包含,那么就会出现编译错误,如果使用@class在两个类的头文件中相互声明,则不会有编译错误出现。
所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.
在Objective-c中,子类可继承父类中的方法,而不需要重新编写相同的方法,直接可以使用父类的方法。
但有时我们不想使用使用父类方法,而是想作一定的修改,怎么办呢?只要将子类中书写一个与父类具有相同的方法名、返回类型和参数,就可以将将父类的方法覆盖重写。这点与Java一样,比较简单.
比如下面IphonePhone中的makeCall:方法就重写了Phone中的makeCall方法.
NSObject类所支持的一些基本方法。
-(BOOL) isKindOf:class-object(判断对象是否是class-object或其子类的成员)
-(BOOL) isMenberOfClass:class-object(判断对象是否是class-object的成员)
-(BOOL) respondsToSelector:selector(判断对象是否能够响应selector所指定的方法)
+(BOOL) instancesRespondToSelector:selector(判断指定的类实例是否能响应selector所指定的方法)
+(BOOL) isSubclassOfClass:class-object(判断对象是否是指定类的子类)
-(id) performSelector:selector(应用selector指定的方法)
-(id) performSelector:selector withObject:object(应用selector指定的方法,传递参数object)
-(id) performSelector:selector withObject:object1 withObject:object2(应用selector指定的方法,传递参数object1和object2)