本章教程主要討論OC的繼承語法以及類的復合編程模式。
OC語法只支持單根繼承,即一個類只能有一個父類。
繼承關鍵字為:
@interface 類目 : 父類名
例如我們昨天聲明的三角形類
@interface Triangle : NSObject
@end
表示Triangle類是繼承與NSObject類。Triangle是NSObject的子類,NSObject是Triangle的父類。
OC語法中規定,通過繼承方式,可以繼承父類的所有方法和除私有權限以外的所有成員變量。
例如上一章的三角形類
@interface Triangle : NSObject
@property double a;
@property double b;
@property double c;
-(instancetype)initWithA:(double)a B:(double)b C:(double)c;
-(double)area;
@end
@implementation Triangle
- (instancetype)initWithA:(double)a B:(double)b C:(double)c
{
self = [super init];
if (self) {
self.a = a;
self.b = b;
self.c = c;
}
return self;
}
-(double)area
{
double s=(_a+_b+_c)/2;
return sqrt(s*(s-_a)*(s-_b)*(s-_c));
}
本章我們可以通過繼承的方法創建一個新的三角形類
@interface TriangleSub : Triangle
@end
@implementation TriangleSub
@end
可以看到我們新創建的TriangleSub類中沒有聲明任何方法也沒有實現任何方法。但是通過繼承語法,我們無償獲得了父類的所有方法和成員變量。
TriangleSub * subT = [[TriangleSub alloc] initWithA:10 B:11 C:12];
double s = [subT area];
NSLog(@"s = %g",s);//NSLog函數是OC中向控制台輸出信息的函數
OC語言是動態類型語言,其表現為調用方法時,不會依據對象指針類型調用對象方法,而根據對象指針使用的內存類型調用響應的方法。
下面通過代碼描述這個特性。
首先我們創建一個測試類TestClass
@interface TestClass : NSObject
-(void)test;
@end
@implementation TestClass
-(void)test
{
NSLog(@"這裡是TestClass類的test方法");
}
@end
我們繼續創建兩個類:
SubA繼承與TestClass
@interface SubA : TestClass
@end
@implementation SubA
//重寫父類的方法
-(void)test
{
NSLog(@"這裡是SubA類的test方法");
}
@end
SubB繼承與TestClass
@interface SubB : TestClass
@end
@implementation SubB
//重寫父類的方法
-(void)test
{
NSLog(@"這裡是SubB類的test方法");
}
@end
現在做如下測試
SubA * a = [[SubB alloc] init];
[a test];//這樣調用沒有編譯錯誤,復合OC的語法規則,那會輸出哪個結果。
根據我們之前講的,OC的動態特性的表現形式
對象指針在調用方法是,不會根據對象指針類型調用響應方法,而是根據對象指針指向的內存類型調用響應的方法
由此可見,對象指針a
的類型為SubA
類型,但其指向的內存類型為SubB
類型。所以用對象指針調用test方法時,會調用SubB
的test方法。
其輸出結果為:這裡是SubB類的test方法。
由於OC語法動態特性的原因,在編寫代碼的過程中,對象指針類型只在編譯時起作用。在運行過程中沒有任何影響。
OC語法推出一個id
關鍵字,表示在編譯過程中不指定類型。
使用id
類型編寫代碼對運行不會有任何影響。但在IDE環境中,變無法開啟代碼自動補全功能,因IDE工具並不知道該對象指針是什麼類型,所以無法進行代碼自動提示和補全。
在OC的復合模式就是把其他對象作為自身的題部分,以提升自身的功能。
比如我現在要制作一台電腦,電腦需要CPU,顯示器,鼠標和鍵盤等。這些東西的研發都是很復雜的過程。如果現在有成型的CPU等組件,就可以直接用這些組件攢一台電腦。復合模式就是這樣。
所有我們在制作電腦前要先找到這些組件。這些組件並不需要我們來制作,有專業的公司提供這些成型的組件。
在本章練習的SDK中提供了如下組件。
KeyBoard 鍵盤類
BigMouse 鼠標類
Monitor 顯示器類
IntelCPU CPU類
下面就用SDK中提供的各種組件來快速制作一台電腦。
首先我們進行電腦類的聲明。需要使用的組件都聲明成屬性,作為電腦類的一部分。
@interface Computer : NSObject
@property(strong, nonatomic) KeyBoard * aKeyBoard;
@property(strong, nonatomic) BigMouse * aMouse;
@property(strong, nonatomic) Monitor * aMonitore;
@property(strong, nonatomic) IntelCPU * aCPU;
@end
在這裡我們先補充一下屬性括號中的內容。
屬性括號中的內容為屬性控制符,分別對屬性的讀寫權限,內存管理和線程操作做出相關規定。
readonly
和readwrite
。其中如果不寫默認為readwrite
。通常屬性的讀寫權限都為可讀可寫。assgin
,strong
,weak
和copy
。如果不寫,默認為assgin
。如果屬性類型為基本數據類型,那麼只能用assgin
。如果屬性類型為對象指針,一般情況下用strong
,特殊情況下用weak
或copy
。特殊情況在後面的內存管理章節會展開講解。atomic
和nonatomic
。其中如果不寫默認為atomic
。通常我們使用nonatomic
作為線程操作,其具體內容在後續的多線程章節會展開講解。
然後繼續實現電腦類,因CPU等組件是電腦的一部分,所以我們需要重新電腦的初始化方法,在電腦初始化的的同時也初始化各種組件,為其分配內存。
@implementation Computer
- (instancetype)init
{
self = [super init];
if (self)
{
self.aKeyBoard = [[KeyBoard alloc] init];
self.aMouse = [[BigMouse alloc] init];
self.aMonitore = [[Monitor alloc] init];
self.aCPU = [[IntelCPU alloc] init];
}
return self;
}
@end
經過聲明組件屬性,為組件的對象指針分配內存。我們就使用成型的組件快速的制作好了一個功能完整的電腦。
通常繼承和復合會一同使用,來快速構造一個復雜的對象。
例如現在有一個需求,要求我們快速制作一個可以除甲醛的高級空調。通常我們並不是從零開始研發,而是基於一定基礎開始制作。
在這裡,我提供了兩個對象作為研發的基礎
以下是Kongtiao類的聲明
@interface Kongtiao : NSObject
-(void)zhiling;
@end
以下是ChuJiaquan類的聲明
@interface ChuJiaQuan : NSObject
-(void)chuJQ;
@end
首先明確我們制作的是一個空調,所有我們創建一個高級空調類繼承與空調類。
然後高級空調需要有除甲醛的功能,我們通過復合模式,把除甲醛的模塊作為高級的空調的一部分。
最後我們重寫父類的制冷方法,在制冷過程中添加除甲醛的步驟。但是在重寫的方法會覆蓋掉父類原有的方法。這裡我們需要在重寫方法中手動調用父類原始方法。就需要用到super
關鍵字。
@interface NewKongtiao : Kongtiao
@property(strong, nonatomic) ChuJiaQuan * cJQ;
@end
@implementation NewKongtiao
- (instancetype)init
{
self = [super init];
if (self)
{
self.cJQ = [[ChuJiaQuan alloc] init];
}
return self;
}
-(void)zhileng
{
[super zhileng];
[self.cJQ chuJQ];
}
@end
這樣我們在使用高級空調制冷的同時,也同時能夠除甲醛了。