多态
1 允许不同的类定义相同的方法
动态类型
1 程序直到执行时才能确定所属的类
静态类型
1 将一个变量定义为特定类的对象时,使用的是静态形态
1 将一个变量定义为特定类的对象时,使用的是静态类型,在编译的时候就知道这个变量所属的类,这个变量总是存储特定类的对象。使用静态类型时,编译器尽可能的确保变量的用法在程序中始终保持一致,编译器能够通过检查来确定应用于对象的方法是由该类定义的或者由该类继承的,否则就会显示警告,静态类型能够更好地在程序编译阶段就指出错误.并且使用静态类型可以提高程序的可读性
1 简单来说: 2 Person *p =[Person new]; 3 编译器判断左右两边类型一致时,就是静态类型 4 Person *p =[Man new]; 5 编译器判断左右两边类型不一致时,就当做动态类型进行处理,随后会判断左右两边是否有类的关联关系
为什么要有动态类型?
1 多态的出现是为了让不同的类能使用同名的方法,这会让程序的可读性大大提高,也降低了编程难度 2 3 编译时和运行时检查 4 5 因为存储在id变量中的对象类型在编译的时候是无法确定的,所以一些事情是需要在运行时才能够确定 6 例如:类Dog只有一个run方法 ,而类Cat只有一个jump方法,那么下面这段代码在编译的时候就会出错 7 Dog *dog =[[Dog alloc]init]; 8 [dog jump]; 9 10 因为编译器知道dog是Dog类的一个对象,而当遇到[dog jump]消息的时候,编译器同样知道Dog类是没有jump方法的,所以在编译器阶段就会提出警告,但是如果将代码换成下面的样子,在编译阶段就不会出错 11 12 Animal *car =[[Dog alloc]init]; 13 [(Cat *) cat jump]; 14 15 因为在编译阶段编译器并不知道cat中存放的对象的类型是什么,所以在运行的时候程序就会crash
id类型及应用场景
1 用NSObject访问子类对象方法 2 //定义id类型 3 NSObject *obj =cat; 4 [(Cat*) obj run];
id类型
1 id是一种通用的对象类型,它可以用来存储属于任何类的对象 2 也可以理解为"万能指针" 3 4 注意:在id的定义中,已经包好了 *号.id指针只能指向os的对象
id类型的定义
1 typedef struct objc object{ 2 3 Class isa; 4 5 }*; 6 局限性:调用一个不存在的方法,编译器会马上报错 7 8 IOS5之后推出了 instancetype类型 9 10 instancetype和id的异同 11 1)相同点 12 都可以作为方法的返回类型 13 2)不同点 14 instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象; 15 instancetype只能作为返回值,不能像id那样作为参数
id类型的应用场景
1 //动物类 2 Animal *animal =[Animal new]; 3 //狗的类,狗继承自动物 4 Dog *dog=[Dog new]; 5 //猫的类,猫继承自动物 6 Cat *cat =[Cat new]; 7 //定义id类型 8 id obj = cat ;//id obj = dog; 9 [obj run]; 10 11 //NSObject 和id 都可以指向任何对象 12 //NSObject 对象进行编译时检查(需要强制类型转换) 13 //id不需要强制类型转换,id可以直接用 14 //编译器看到id以后,认为是动态类型,不在检测类型
动态绑定
1 1)在objective-c 中,一个对象内是否调用指定的方法不是由编译器决定而是由运行时决定,这被称作是方法的动态绑定。 2 2)在objective-c里,对象不调用方法,而是接收消息,消息 表达式:[reciver message];运行时系统首先确定接收者的类型(动态类型识别),然后根据消息名在类的方法列表里选择相依的方法执行,所以在源代码里消息也称为选择器(selector) 3 3)消息函数的作用: 4 首先通过第一个参数的receiver,找到它的isa指针,然后在isa指向的Class对象中使用第二个参数selector查找方法 5 如果没有找到,就使用当前Class对象中的新的isa指针到上一级的父类的Class 对象中查找 6 当找到方法后,再依据receiver的中的self 指针找到当前的对象,调用当前对象的具体实现的方法(IMP),然后传递参数,调用实现方法 7 假如一致找到NSObject的Class对象,也没有找到你调用的方法,就会报告不能识别发送信息的错误
动态类型检测方法
1 对象再运行时获取其类型的能力称为内省,内省可以有多种方法实现 2 1)判断类型 3 -(BOOL)isKindOfClass:clasObj 判断实例对象是否是这个类或者这个类的子类的实例 4 格式 : 5 对象 isKindOfClass:类对象 6 7 例: 8 Animal *ani= [Animal new]; 9 BOOL isInstance=[ani isKindOfClass: [Animal class]]; 10 11 2) 12 -(BOOL)isMemberOfClass:classObj 判断是这个类的实例,不包括子类对象 13 14 格式: 15 对象 isMemberofClass:类对象 16 例如: 17 BOOL isINstance=[dog isMemberofClass:Animal class]];//NO =0 ; 18 19 3) 20 -(BOOL)isSubclassOfClass:classObj 判断类是否是指定类的子类
判断实例对象能否相应指定的方法
1 判断实例是否有这样的方法 2 -(BOOL) respondsToSelector:seletor 3 4 例: 5 Animal *ani =[Animal new]; 6 SEL s1 = @selector(eat);//把eat包装成SEL类型 7 BOOL isRespond=[ani respondsToSelector:(s1)]
响应方法
1 应用selector指定的方法 2 -(id)performSelector:selector 3 4 //动态类型检测:响应方法 5 Animal *ani =[Animal new]; 6 7 if([ani respondsToSelector:@selector(eat)]){ 8 9 }else{ 10 NSLog(@"这个方法不能被响应"); 11 } 12 13 响应方法: 14 Animal *ani =[Animal new]; 15 16 SEL s1= @selector(eat); 17 if([ani respondsToSelector:s1]){ 18 [ani performSelector:s1];//作用,响应方法 19 }else{ 20 21 } 22 23 //多参数 performSelector:s2 withObject: 24 SEL s2 =@selector(eat:); 25 [ani performSelector:s2 withObject:@""] 26 27 [ani performSelector:@selector(eat: andFoodName:)withObject:@"班长养得饿狗" withObject:@""]