1.靜態(tài)類型和動態(tài)類型
- 靜態(tài)類型
- 將一個指針變量定義為特定類的對象時,使用的是靜態(tài)類型,在編譯的時候就知道這個指針變量所屬的類,這個變量總是存儲特定類的對象危队。
Person *p = [Person new];
- 動態(tài)類型
- 這一特性是程序直到執(zhí)行時才確定對象所屬的類
id obj = [Person new];
2.為什么要有動態(tài)類型?
- 我們知道NSObject是OC中的基類
- 那么任何對象的NSObject類型的指針可以指向任意對象,都沒有問題
- 但是NSObject是靜態(tài)類型微峰,如果通過它直接調(diào)用NSObject上面不存在的方法北秽,編譯器會報錯锄蹂。
- 你如果想通過NSObject的指針調(diào)用特定對象的方法,就必須把NSObject * 這種類型強(qiáng)轉(zhuǎn)成特定類型坦仍。然后調(diào)用鳍烁。如下
//定義NSObject * 類型
NSObject* obj = [Cat new];
Cat *c = (Cat*)obj;
[c eat];
- id 是一種通用的對象類型,它可以指向?qū)儆谌魏晤惖膶ο?也可以理解為萬能指針 ,相當(dāng)于C語言的 void *
- 因為id是動態(tài)類型,所以可以通過id類型直接調(diào)用指向?qū)ο笾械姆椒? 編譯器不會報錯
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
id obj = [C at new];
[obj eat]; // 不用強(qiáng)制類型轉(zhuǎn)換
[obj test]; //可以調(diào)用私有方法
- 注意:
- 在id的定義中,已經(jīng)包好了*號。id指針只能指向OC中的對象
- 為了盡可能的減少編程中出錯繁扎,Xcode做了一個檢查幔荒,當(dāng)使用id 類型的調(diào)用本項目中所有類中都沒有的方法,編譯器會報錯
- id類型不能使用.語法, 因為.語法是編譯器特性, 而id是運行時特性
3.id數(shù)據(jù)類型與靜態(tài)類型
-
雖然說id數(shù)據(jù)類型可以存儲任何類型的對象梳玫,但是不要養(yǎng)成濫用這種通用類型
- 如沒有使用到多態(tài)盡量使用靜態(tài)類型
- 靜態(tài)類型可以更早的發(fā)現(xiàn)錯誤(在編譯階段而不是運行階段)
- 靜態(tài)類型能夠提高程序的可讀性
- 使用動態(tài)類型前最好判斷其真實類型
-
動態(tài)類型判斷類型
- —— (BOOL)isKindOfClass:classObj 判斷實例對象是否是這個類或者這個類的子類的實例
Person *p = [Person new];
Student *stu = [Student new];
BOOL res = [p isKindOfClass:[Person class]];
NSLog(@"res = %i", res); // YES
res = [stu isKindOfClass:[Person class]];
NSLog(@"res = %i", res); // YES
- (BOOL) isMemberOfClass: classObj 判斷是否是這個類的實例
Person *p = [Person new];
Student *stu = [Student new];
BOOL res = [p isMemberOfClass:[Person class]];
NSLog(@"res = %i", res); // YES
res = [stu isMemberOfClass:[Person class]];
NSLog(@"res = %i", res); // NO
+ (BOOL) isSubclassOfClass:classObj 判斷類是否是指定類的子類
BOOL res = [Person isSubclassOfClass:[Student class]];
NSLog(@"res = %i", res); // NO
res = [Student isSubclassOfClass:[Person class]];
NSLog(@"res = %i", res); // YES