標籤:
繼承、初始化方法、便利構造器
今天我們要學習繼承 初始化方法 以及遍曆構造器 首先我們要理解一些概念性的東西.
繼承: 在OC裡,繼承是單繼承的,所謂的單繼承就是一個子類繼承一個父類,例如我們之前建立的Person類是繼承於NSObject的.回顧一下繼承的格式
@interface Person : NSObject //在冒號後面是繼承的父類. 人繼承與NSObject
子類是只能繼承一個父類,但父類卻可以有多個子類.例如:
@interface Student : Person // 學生繼承於Person類
@interface Teacher : Person // 老師繼承與Person類 老師,學生都是人類
繼承的用處: 可以大大的減輕代碼量,同時也將子類所擁有的共性結合到一塊了,共有的屬性就可以寫在父類中,在使用的時候,子類可以直接調用.
例如:人類 老師和學生 他們都會由名字name 性別sex 年齡age等共同的屬性,這樣就一次性寫在父類Person中就可以了.然而子類單獨擁有的
屬性,就單獨的寫在自己的類中. 例如老師有工資, 學生交學費 這樣不同的屬性.
@interface Person : NSObject
{
下面三個執行個體是老師和學生都共同擁有的,所以寫在他們所繼承的父類Person裡
_name = name;
_sex = sex;
_age = age;
}
@interface Teacher : Person
{
工資是老師單獨擁有的屬性,所以寫在Teacher類中
_salary = salary;
}
@interface Student : Person
{
交學費是學生單獨擁有的屬性,所以寫在student類中
_schooling = schooling;
}
初始化方法:
眾所周知,Objective-C是一門物件導向的語言,一般情況下,我們在Objective-C中定義一個類時,總要提供一個初始化方法,一般大家都是這樣寫的:
- (id)init
{
self = [super init];
if (self) {
執行一些資源、變數的初始化工作
}
return self;
}
這樣一段簡單的代碼,卻有很多可以思考的問題:
1、為什麼要通過[super init]來調用父類的初始化方法,父類的初始化方法裡又執行了什麼東西?
首先,我們知道對象繼承的概念,一個子類從父類繼承,那麼也要實現父類的所有功能,這就是is-a的關係,比如說上面提到的老師(Teacher)和
學生(Student)都是人,那麼Teacher和Student就都回有Person的特徵和功能。所以在子類的初始化方法中,必須首先調用父類的初始化方法,
以實現父類相關資源的初始化。例如我們在初始化Teacher這一對象時,必須先初始化Person類這一對象,並把結果賦予Teacher,以使Teacher
滿足Person這一特徵。典型的,在iOS下,所有的類都繼承於NSObject,而NSObject的init方法很簡單,就是return self。當父類的初始化完成
之後,即self不為nil的情況下,就可以開始做子類的初始化了。
2、是否一定要提供初始化方法,是否一定要使用init作為初始化方法?
我們在Objective-C中建立一個對象通常使用
Person *per = [[Person alloc] init];
或者
Person *per = [Person new];
new方法是NSObject對象的一個靜態方法,根據apple的文檔,該方法實際上就是alloc和init方法的組合,實際上二者是一樣的,但 apple還是推
薦我們使用第一種方法,為什麼呢?因為使用第一種方法,你可以使用自己定義的init方法來做一些初始化,當然,如果子類沒有提供 init方法,自
然調用的就是父類的init方法了。所以說,從安全性的角度來收,作為開發人員我們在對象使用之前是一定要對對象進行初始化的,因此在定義類的時
候一定要提供初始化方法。但是否一定要使用init作為方法名呢?答案是不一定。使用init作為方法名只是你重寫了NSObject的init方法而已,如果
你自己重新定義一個初始化方法,也是完全可以的,只要你在使用的時候記得調用新定義的初始化方法就可以了。
但是,這種方法從設計角度來看我覺得是不可取的。在可複用性方面會比較差,如果確有必要定義一些接受不同參數的初始化方法,我的建
議是,先定義一個init的公用方法,再到其他方法中調用它,如:
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (id)initWithName:(NSString *)name
{
[self init];
_name = name;
}
- (id)initWithAge:(NSInteger)age
{
[self init];
_age = age;
}
補充:
在物件導向編程中,如果編寫一個類而沒有包含建構函式,這個類仍能編譯並且完全可以正常使用。如果類沒有提供顯式的建構函式,編譯
器會提供一個預設的建構函式給你。除了建立對象本身,預設建構函式的唯一工作就是調用其超類的建構函式。在很多情況下,這個超類是語言框
架的一部分,如java中的 Object類,objective-c 中的NSObject類。
不論是何種情況,在類中至少包含一個建構函式是一種很好的編程實踐,如果類中有屬性,好的實踐往往是初始化這些屬性。
——以上摘自《The Object-Oriented Thought Process》 by Matt Weisfeld
Person *per = [[Person alloc] init];//alloc是類方法,init是執行個體方法,Person alloc建立了一個對象(per),然後調用per對象的init方法進行該對象的初始化.
- [(id)initWithName: (NSString *)name
age: (NSInteger)age
{
if(self = [super init])
//這裡不是判斷self與[super init]是否相等,而是判斷是否可以成功初始化. 而用if判斷下,是位了方式self為空白的情況
_name = name;
_age = age;
}
+(id)personWithName: (NSString *)name
age:(NSInteger)age
{
id obj = [[Person alloc] initWithName:name age:age];
//設定obj的值
return obj;
}
//調用方法
Person *per = [Person alloc]personWithName:@"Jack" age:30];
//本方法調用了上方+號類方法,也就是便利構造器的初始化方法
Objective-C 繼承、初始化方法、便利構造器