- 不要等到明天,明天太遙遠,今天就行動。
須讀:看完該文章你能做什么?
1.靜態數據類型 和 動態數據類型的一個認識。
2.如何創建動態數據類型id類型
3.判斷 指定對象 是不是某一個類,或者是子類isKindOfClass
判斷指定的對象 是不是當前指定的類的實例isMemberOfClass
判斷指定的類,是不是另外一個類的子類isSubclassOfClass
學習前:你必須會什么?
什么繼承、什么多態。
1.繼承是 B類 繼承 A類 ,那么 B類擁有A類的所有屬性和方法,并且B類擁有自己的私有屬性和方法。
2.多態是 某一類事物的多種形態。比如 貓->貓->動物
父類指針 指向 子類對象
動物的指針 指向了 貓 (這就是多態) 貓是動物
動物 *a = [貓 new];
一、本章筆記
一、靜態數據類型和動態數據類型的特點
id是一個數據類型, 并且是一個動態數據類型
既然是數據類型,所以就可以用來
1.定義變量
2.作為函數的參數
3.作為函數的返回值
默認情況下 所有的數據類型 都是靜態數據類型
靜態數據類型的特點:
在編譯時 就知道變量的類型,
知道變量中哪些屬性 和 方法
在編譯的時候 就可以訪問這些屬性 和 方法,
并且 如果是通過靜態數據類型定義變量,
如果訪問了不屬于靜態數據類型的屬性和方法,那么編譯器會報錯 (如:p 訪問 eat方法)
動態數據類型的特點:
在編譯的時候 編譯器并不知道 變量的真是類型, 只有在運行的時候 才知道它的真實類型
并且 如果通過動態數據類型定義變量, 如果訪問了不屬于動態類型數據的屬性和方法,編譯器不會報錯
id == NSObject * 萬能指針
id 和 NSObject *的區別:
NSObject * 是一個靜態數據類型
id 是一個動態數據類型
二、靜態數據類型
例子
NSObject *obj = [Person new];
// [obj sleep];
// [obj test];
NSObject *obj2 = [Student new];
三、動態數據類型
>>動態數據類型 (id) 編譯器在編譯的時候不知道動態數據的真正類型,所以在編譯的時候放你一馬,然后到運行的時候才會監測你的類型
通過靜態數據類型 定義變量, 不能調用子類特有的方法
通過動態數據類型 定義變量, 可以調用子類特有的方法
弊端: 由于動態數據類型可以調用任何方法,所以有可能調用到不屬于自己的方法,所以會導致運行時的錯誤
應用場景 : 多態, 可以減少代碼量, 避免調用子類特有的方法 需要強制類型轉換
四、為了避免動態數據類型 引發的運行時的錯誤,一般情況下 如果使用動態數據類型定義一個變量,在調用這個變量的方法之前會進行一次判斷,判斷當前變量是否能夠調用這個方法
1.isKindOfClass , 判斷指定的對象 是不是某一個類, 或者是某一個類的子類
2.isMemberOfClass , 判斷指定的對象 是不是當前指定的類的實例
3.isSubclassOfClass -- A isSubclassOfClass [B class] 判斷 A 是不是 B 的子類
注意、盡量讓錯誤發生在編譯時,如果在編譯時,能夠及時檢查錯誤.
二、code
main.m
#pragma mark 06-動態數據類型
#pragma mark 概念
/*
一、靜態數據類型和動態數據類型的特點
id是一個數據類型, 并且是一個動態數據類型
既然是數據類型,所以就可以用來
1.定義變量
2.作為函數的參數
3.作為函數的返回值
默認情況下 所有的數據類型 都是靜態數據類型
靜態數據類型的特點:
在編譯時 就知道變量的類型,
知道變量中哪些屬性 和 方法
在編譯的時候 就可以訪問這些屬性 和 方法,
并且 如果是通過靜態數據類型定義變量,
如果訪問了不屬于靜態數據類型的屬性和方法,那么編譯器會報錯 (如:p 訪問 eat方法)
動態數據類型的特點:
在編譯的時候 編譯器并不知道 變量的真是類型, 只有在運行的時候 才知道它的真實類型
并且 如果通過動態數據類型定義變量, 如果訪問了不屬于動態類型數據的屬性和方法,編譯器不會報錯
id == NSObject * 萬能指針
id 和 NSObject *的區別:
NSObject * 是一個靜態數據類型
id 是一個動態數據類型
二、靜態數據類型
例子
NSObject *obj = [Person new];
// [obj sleep];
// [obj test];
NSObject *obj2 = [Student new];
三、動態數據類型
>>動態數據類型 (id) 編譯器在編譯的時候不知道動態數據的真正類型,所以在編譯的時候放你一馬,然后到運行的時候才會監測你的類型
通過靜態數據類型 定義變量, 不能調用子類特有的方法
通過動態數據類型 定義變量, 可以調用子類特有的方法
弊端: 由于動態數據類型可以調用任何方法,所以有可能調用到不屬于自己的方法,所以會導致運行時的錯誤
應用場景 : 多態, 可以減少代碼量, 避免調用子類特有的方法 需要強制類型轉換
四、為了避免動態數據類型 引發的運行時的錯誤,一般情況下 如果使用動態數據類型定義一個變量,在調用這個變量的方法之前會進行一次判斷,判斷當前變量是否能夠調用這個方法
1.isKindOfClass , 判斷指定的對象 是不是某一個類, 或者是某一個類的子類
2.isMemberOfClass , 判斷指定的對象 是不是當前指定的類的實例
3.isSubclassOfClass -- A isSubclassOfClass [B class] 判斷 A 是不是 B 的子類
注意、盡量讓錯誤發生在編譯時,如果在編譯時,能夠及時檢查錯誤.
*/
#pragma mark - 代碼
#import <Foundation/Foundation.h>
#pragma mark 類
#import "Person.h"
#import "Student.h"
#pragma mark - main函數
int main(int argc, const char * argv[])
{
/*
id是一個數據類型, 并且是一個動態數據類型
既然是數據類型,所以就可以用來
1.定義變量
2.作為函數的參數
3.作為函數的返回值
默認情況下 所有的數據類型 都是靜態數據類型
靜態數據類型的特點:
在編譯時 就知道變量的類型,
知道變量中哪些屬性 和 方法
在編譯的時候 就可以訪問這些屬性 和 方法,
并且 如果是通過靜態數據類型定義變量,
如果訪問了不屬于靜態數據類型的屬性和方法,那么編譯器會報錯 (如:p 訪問 eat方法)
動態數據類型的特點:
在編譯的時候 編譯器并不知道 變量的真是類型, 只有在運行的時候 才知道它的真實類型
并且 如果通過動態數據類型定義變量, 如果訪問了不屬于動態類型數據的屬性和方法,編譯器不會報錯
id == NSObject * 萬能指針
id 和 NSObject *的區別:
NSObject * 是一個靜態數據類型
id 是一個動態數據類型
*/
#pragma 測試
/*
Person *p = [Person new];
p.age = 25;
[p sleep];
// [p eat];
*/
/*
Person *p = [Student new];
p.age = 25;
[p sleep];
[(Student *)p eat];
// Student *s = (Student *)p;
// [s eat];
*/
#pragma 靜態數據類型
/*
NSObject *obj = [Person new];
// [obj sleep];
// [obj test];
NSObject *obj2 = [Student new];
*/
#pragma 動態數據類型 (id) 編譯器在編譯的時候不知道動態數據的真正類型,所以在編譯的時候放你一馬,然后到運行的時候才會監測你的類型
#warning 盡量讓錯誤發生在編譯時,如果在編譯時,能夠及時檢查錯誤.
// 通過靜態數據類型 定義變量, 不能調用子類特有的方法
// 通過動態數據類型 定義變量, 可以調用子類特有的方法
// 弊端: 由于動態數據類型可以調用任何方法,所以有可能調用到不屬于自己的方法,所以會導致運行時的錯誤
// 應用場景 : 多態, 可以減少代碼量, 避免調用子類特有的方法 需要強制類型轉換
/*
typedef struct objc_object {
Class isa;
} id;
Description
A pointer to an instance of a class.
Availability iOS (4.0 and later), macOS (10.6 and later), tvOS (9.0 and later), watchOS (2.0 and later)
Declared In Objective-C
More Structure Reference
*/
/*
id obj = [Person new];
[obj sleep];
[obj test];
// Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person eat]: unrecognized selector sent to instance 0x1002014b0'
[obj eat]; // 父類 調用 子類方法
id obj2 = [Student new];
[obj2 eat];
*/
#pragma 為了避免動態數據類型 引發的運行時的錯誤,一般情況下 如果使用動態數據類型定義一個變量,在調用這個變量的方法之前會進行一次判斷,判斷當前變量是否能夠調用這個方法
// id obj = [Person new];
id obj = [Student new];
if ([obj isKindOfClass:[Student class]]) {
// // isKindOfClass , 判斷指定的對象 是不是某一個類, 或者是某一個類的子類
// if ([obj isMemberOfClass:[Student class]]) {
// isMemberOfClass , 判斷指定的對象 是不是當前指定的類的實例
// if([Student isSubclassOfClass:[Person class]]){
// isSubclassOfClass -- A isSubclassOfClass [B class] 判斷 A 是不是 B 的子類
[obj eat];
}
NSLog(@"----");
return 0;
}
Person
>>>.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property int age;
- (void)sleep;
@end
>>>.m
#import "Person.h"
@implementation Person
- (void)sleep
{
NSLog(@"睡覺");
}
- (void)test
{
NSLog(@"私有方法 test");
}
@end
Student
>>>.h
#import <Foundation/Foundation.h>
@interface Student : NSObject
- (void)eat;
@end
>>>.m
#import "Student.h"
@implementation Student
- (void)eat
{
NSLog(@"吃飯");
}
@end