id是一個數據類型, 并且是一個動態數據類型
既然是數據類型, 所以就可以用來
1.定義變量
2.作為函數的參數
3.作為函數的返回值
默認情況下所有的數據類型都是靜態數據類型
靜態數據類型的特點:
在編譯時就知道變量的類型,
知道變量中有哪些屬性和方法
在編譯的時候就可以訪問這些屬性和方法,
并且如果是通過靜態數據類型定義變量, 如果訪問了不屬于靜態數據類型的屬性和方法, 那么編譯器就會報錯
動態數據類型的特點:
在編譯的時候編譯器并不知道變量的真實類型, 只有在運行的時候才知道它的真實類型
并且如果通過動態數據類型定義變量, 如果訪問了不屬于動態數據類型的屬性和方法, 編譯器不會報錯
id == NSObject * 萬能指針
id和NSObject *的區別:
NSObject *是一個靜態數據類型
id ?是一個動態數據類型
Person *p = [Person new];
p.age = 30;
[p sleep];
Person *p = [Student new];
p.age = 30;
[p sleep];
// ? ?[p eat];
Student *stu = (Student *)p;
[stu eat];
NSObject *obj = [Person new];
[obj test];
NSObject *obj2 = [Student new];
// 通過靜態數據類型定義變量, 不能調用子類特有的方法
// 通過動態數據類型定義變量, 可以調用子類特有的方法
// 通過動態數據類型定義的變量, 可以調用私有方法
// 弊端: 由于動態數據類型可以調用任意方法, 所以有可能調用到不屬于自己的方法, 而編譯時又不會報錯, 所以可能導致運行時的錯誤
// 應用場景: 多態, 可以減少代碼量, 避免調用子類特有的方法需要強制類型轉換
id obj = [Person new];
[obj sleep];
[obj test];
[obj eat];
id obj2 = [Student new];
[obj2 eat];
[obj2 test];
// 為了避免動態數據類型引發的運行時的錯誤, 一般情況下如果使用動態數據類型定義一個變量, 在調用這個對象的方法之前會進行一次判斷, 判斷當前對象是否能夠調用這個方法
// ? ?id obj = [Person new];
id obj = [Student new];
if ([obj isKindOfClass:[Student class]]) {
// isKindOfClass , 判斷指定的對象是否是某一個類, 或者是某一個類的子類
[obj eat];
}
if ([obj isMemberOfClass:[Student class]]) {
// isMemberOfClass : 判斷指定的對象是否是當前指定的類的實例
[obj eat];
}