1. 類方法和對象方法
對象方法
- 減號 - 開頭
- 只能由對象來調(diào)用
- 對象方法中能訪問當(dāng)前對象的成員變量(實例變量)
類方法
- 加號 + 開頭
- 只能由類(名)來調(diào)用
- 類方法中不能訪問成員變量(實例變量)
類方法的好處和使用場合
- 不依賴于對象,執(zhí)行效率高
- 能用類方法,盡量用類方法
- 場合:當(dāng)方法內(nèi)部不需要使用到成員變量時,就可以改為類方法
可以允許類方法和對象方法同名
2. self 關(guān)鍵字
self 的用途
- 誰調(diào)用了當(dāng)前方法,self就代表誰
- self出現(xiàn)在 對象/類 方法中,self就代表 對象/類
- 成員變量和局部變量重名
當(dāng)成員變量和局部變量同名時,采取就近原則,訪問的是局部變量
用self訪問成員變量,區(qū)分同名的局部變量
使用細(xì)節(jié)
- 出現(xiàn)的地方:所有的OC方法中(對象方法\類方法),不能出現(xiàn)在函數(shù)
- 作用
使用 "self->成員變量名" 訪問當(dāng)前 對象\類 方法調(diào)用的成員變量
使用 "[self 方法名];" 來調(diào)用方法(對象方法\類方法)
3. 繼承
好處:
- 抽取重復(fù)代碼
- 建立類之間的關(guān)系
- 子類可以擁有父類中 所有的 成員變量 和 方法
壞處:增強了代碼的耦合性
重寫:子類 重新實現(xiàn) 父類的某個方法,覆蓋父類以前的方法
使用情境:
- A是B,則A繼承B
- A擁有B,則A組合B「即B為A內(nèi)部的一個成員變量」
super 關(guān)鍵字
- 直接調(diào)用父類的 成員變量 和 對象方法
- 使用情景:子類重寫父類方法時想保留父類的一些行為
注意
- Objective-C 是 單繼承
- 基本上所有類的根類是NSObject
- 不允許子類和父類擁有相同名稱的成員變量
- 父類必須聲明在子類前面「實現(xiàn)不用在子類前」
- 調(diào)用某個對象/類的方法時,優(yōu)先去當(dāng)前 對象/類 中找,若找不到去父類中找
- 子類會繼承父類所有的變量「不管是否是私有,只是能不能直接訪問的問題」
- 父類只在 implementation 里定義的變量,子類也會繼承
4. 多態(tài)「多種形態(tài)」
定義:父類指針 指向 子類對象
作用:若參數(shù)中使用的父類類型,則可以傳入父類、子類對象
注意
- 編譯時 編譯器會檢查當(dāng)前類型對應(yīng)的類中有沒有調(diào)用方法「因為OC是弱語法」
- 運行時 系統(tǒng)會動態(tài)檢測對象的真實類型
- 局限性:父類型變量不能直接調(diào)用子類的方法「可以通過強制轉(zhuǎn)換來實現(xiàn)」
5. 對象和對象的關(guān)系
組合關(guān)系:類型相同 或 實現(xiàn)同一接口 的對象組合到一起
依賴關(guān)系:A對象 做 B對象的 形參 或 方法的局部變量,B 依賴 A
關(guān)聯(lián)關(guān)系:A對象 做 B對象的 一個成員變量,A 和 B 有關(guān)聯(lián)關(guān)系
6. 構(gòu)造方法
完整的創(chuàng)建一個對象「new 方法的步驟」
- 調(diào)用 +alloc 方法,分配存儲空間,返回一個對象 Cat *c = [Cat alloc];
- 調(diào)用 -init 方法,進(jìn)行初始化,把成員變量的值初始化為 0,返回初始化的原來對象 c = [c init];
[Cat new] == [[Cat alloc] init]
目的:對象創(chuàng)建出來,成員變量就有一些固定的值
方法:
- 重寫 - init 方法
// implementation 中
- (instancetype)init {
// 1.調(diào)用 父類「super」 的 init 方法:初始化父類中聲明的 成員變量屬性 和 其他屬性
self = [super init]; // 得到當(dāng)前對象 self
if (self != nil) { // 初始化成功,nil 是空 == 0
_min = 10; // 2. 進(jìn)行子類內(nèi)部成員的初始化
}
return self;// 返回已經(jīng)初始化完畢的對象
}
- 自定義構(gòu)造方法
// implementation 中
- (instancetype)initWithAge : (int)age {
// 簡化寫法
if (self = [super init]) {
_age = age;
}
return self;
}
7. 類的聲明可以不寫「僅僅警告」
- 有類的聲明
// 聲明
@interface Sample : NSObject {
// 可以有成員變量
int a; // 默認(rèn)@protected}
- (void)test;
@end
// 實現(xiàn)
@implementation Sample {
// 也可以有成員變量「這種做法很少見」
int b; // 默認(rèn) @private
//注意:interface 和 implementation 不能聲明同名的成員變量
}
- (void)test{
NSLog(@"有類的聲明");
}
@end
- 沒有類的聲明「實現(xiàn) 必須寫在main函數(shù)之前」
// 實現(xiàn)
@implementation Sample : NSObject
- (void)test{
NSLog(@"沒有類的聲明");
}
@end
8. id 和 instancetype 數(shù)據(jù)類型
實質(zhì):id 和 instancetype 都是 萬能指針類型,能 指向/操作 任何 objc 對象
區(qū)別:
- id 在編譯時,不能 判斷對象的真實類型
可以 定義變量,作為返回值,作為形參 - id 不能用點語法,id可以調(diào)用任何對象的方法「這樣不利于編譯器檢查錯誤」
- instancetype 編譯時,判斷對象的真實類型
只能用于返回值
注意:自定義構(gòu)造方法 返回值 盡量使用 instancetype 而不是 id
用法:
id d = [Person new]; // d為指針,id 類似于 NSObject *
NSObject *o = [Person new];
9. @class 關(guān)鍵字
- 格式:@class 類名1, 類名2 「注:為了可讀性,一般一個@class 對應(yīng)一個類名」
- 僅僅告訴編譯器 類名 是個類,防止兩個類互相調(diào)用.h文件 編譯器報錯
- 開發(fā)中引用的 類規(guī)范:
- 在 .h 文件中用 @class 來聲明
- 在 .m 文件中用 #import 來包含類所有的東西
- @class 優(yōu)點:
多個頭文件 #import 了同一個頭文件 a時,若 a 稍有改動,則這多個頭文件就都要重新編譯,為了減輕編譯器的負(fù)擔(dān) 使用 @class
10. 類的本質(zhì)
類對象:類本身也是個對象,是 Class 類型對象
Class 類型定義:<code>typedef struct objc_class *Class;</code>
為了調(diào)用類方法,獲取類對象「對象的類」:<code>Class n = [對象名 class];</code> 或 <code>Class n = [類名 class];</code>
11. 分類 Category
作用:在不改變原來類內(nèi)容的基礎(chǔ)上,為類添加方法「繼承也有這樣的作用」
好處:一個龐大的類可以分模塊開發(fā),由多人編寫,更有利于團隊合作
用法:分類可以定義在 單獨的 .m文件和 .h文件中,也可以定義在原來類中
- 一般情況下,都定義在單獨文件中
- 定義在原來類中的分類,只要能看懂語法就好
格式:
- 在 原類名+分類名.h 文件中「文件名是規(guī)范」
#import "原類名.h"
@interface 類名 (分類名)
// 方法聲明;
@end
- 在 原類名+分類名.m 文件中
#import "原類名+分類名.h"
@implementation 類名 (分類名)
// 方法實現(xiàn)
@end;
注意:
- 分類只能增加 方法,不能增加 成員變量
- 分類方法可以訪問原來類的成員變量
- 分類可以覆蓋原來類同名的方法,會使類中原來的方法失效
- 方法調(diào)用優(yōu)先級:1.分類「最后參與編譯的分類優(yōu)先」→ 2.原來類 → 3.父類
12. Class Extension 類擴展
定義:匿名的 Category,寫在 .m/.h 文件中
作用:為某個類擴充一些私有的 成員變量 和 方法 的聲明
格式:
#import "A.h" // 在 .m 文件中
// 類擴展
@interface A(){
int _a; // 私有的成員變量 _a
}
- (void)sum(int) :a addWith :(int)b; // 是聲明
@end
@implementation A {
int _b;
}
- (void)function{
// 實現(xiàn)
}
@end