一、概述
动态绑定:在Objective-C中,一个对象能否调用指定的方法不是由编译器决定的,而是由运行时决定,这种机制称作方法的动态绑定。
在Objective-c里,对象不调用方法,而是接受消息,消息表达式为:[reciver message];运行时系统首先确定接受者的类型(动态类型识别),然后根据消息名在类的方法列表里选择相应的方法执行,所以在源代码里消息也成为选择器(selector)。
消息函数的作用:
首先通过第一个参数receiver找到他的ISA指针,然后ISA执行的class对象中使用 第二个参数selector查找方法:
如果没有找到,就使用当前class对象中的新的ISA指针到上一级父类的class对象中查找;
当找到方法后,在依据receiver中的self指针找到当前对象,调用当前对象的具体实现的方法,然后传递参数,调用实现方法;
如果一直到找到NSObject的class对象也没有找到所调用的方法,就会报告不能识别发送消息的错误。
动态类型检测:
为了防止编译通过但是运行时报错,可以在代码中添加对动态类型检测的方法,在编译时发现不能调用的方法的错误。
对象在运行时获取其类型的能力成为内省。内省可以有多种方法实现,介绍一下三种方法:isKindOfClass; isMemberOfClass; isSubclassOfClass.
二、动态类型
1.isKindOfClass
判断实例对象是否是指定类或者子类的对象,返回BOOL类型。
对象 isSubclassOfClass:[类 class]
2.isMemberOfClass
判断实例对象是否是指定类的对象,返回BOOL类型。
对象 isMemberOfClass:[类 class]
3.isSubclassOfClass
判断一个类是否是指定类或者是其子类,返回BOOL类型。
类 isSubclassOfClass:[类 class]
示例代码:
Animal.h
#import <Foundation/Foundation.h>
@interface Animal : NSObject
-(void) run;
@end
Animal.m
#import "Animal.h"
@implementation Animal
-(void) run{
NSLog(@"Animal running!");
}
@end
Dog.h
#import "Animal.h"
@interface Dog : Animal
-(void) run:(int)speed;
-(void) eat;
@end
Dog.m
#import "Dog.h"
@implementation Dog
-(void)run:(int)speed{
NSLog(@"the dog run with %d km/h",speed);
}
-(void)eat{
NSLog(@"Dog eating!");
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Dog.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Animal *a = [Animal new];
Dog *d = [Dog new];
//1.isKindOfClass
BOOL b1 = [a isKindOfClass:[Animal class]]; //同一个类的对象 1
BOOL b2 = [d isKindOfClass:[Animal class]]; //子类的对象 1
BOOL b3 = [a isKindOfClass:[Dog class]]; //其他 0
NSLog(@"\nisKindOfClass");
NSLog(@"结果:%d",b1); //输出:结果:1
NSLog(@"结果:%d",b2); //输出:结果:1
NSLog(@"结果:%d",b3); //输出:结果:0
//2.isMemberOfClass
BOOL b4 = [a isMemberOfClass:[Animal class]]; //同一个类的对象 1
BOOL b5 = [d isMemberOfClass:[Animal class]]; //子类的对象 0
NSLog(@"\nisMemberOfClass");
NSLog(@"结果:%d",b4); //输出:结果:1
NSLog(@"结果:%d",b5); //输出:结果:0
//3.isSubclassOfClass
BOOL b6 = [Animal isSubclassOfClass:[Animal class]]; //同一个类 1
BOOL b7 = [Dog isSubclassOfClass:[Animal class]]; //子类 1
BOOL b8 = [Animal isSubclassOfClass:[Dog class]]; //其他 0
NSLog(@"\nisSubclassOfClass");
NSLog(@"结果:%d",b6); //输出:结果:1
NSLog(@"结果:%d",b7); //输出:结果:1
NSLog(@"结果:%d",b8); //输出:结果:0
}
return 0;
}
三、判断对象能否响应指定方法
1.respondsToSelector
判断对象能否响应指定方法
对象名 respondsToSelector:@selector(方法名)
2.instancesRespondToSelector
判断类是否拥有指定方法
类名 instancesRespondToSelector:@selector(方法名)
示例代码:
#import <Foundation/Foundation.h>
#import "Dog.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Animal *a = [Animal new];
Dog *d = [Dog new];
//1.判断对象能否响应指定方法
//respondsToSelector
SEL s1 = @selector(run:);
BOOL b11 = [a respondsToSelector:s1]; //Animal 对象是否可以响应run:方法
BOOL b12 = [d respondsToSelector:s1]; //Dog 对象是否可以响应run:方法
NSLog(@"\nrespondsToSelector");
NSLog(@"结果:%d",b11); //输出:结果:0
NSLog(@"结果:%d",b12); //输出:结果:1
//2.判断类是否拥有指定方法
//instancesRespondToSelector
SEL s2 = @selector(eat);
BOOL b13 = [Animal instancesRespondToSelector:s2];
BOOL b14 = [Dog instancesRespondToSelector:s2];
NSLog(@"\ninstancesRespondToSelector");
NSLog(@"结果:%d",b13); //输出:结果:0
NSLog(@"结果:%d",b14); //输出:结果:1
}
return 0;
}
注意:run方法是Animal中的方法,Dog继承了该方法。而run: 方法是Dog类中新增加的方法,Animal中是没有的。(注意run方法和run:方法的区别)
四、响应方法
performSelector
对象名 performSelector:@selector(方法名)
performSelector允许带有参数,但是参数最多不能超多两个,而且是id类型。
对象名 performSelector:@selector(方法名)withObject:参数1 withObject:参数2
示例代码:
#import <Foundation/Foundation.h>
#import "Dog.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Animal *a = [Animal new];
Dog *d = [Dog new];
SEL s3 = @selector(run);
NSLog(@"\nperformSelector");
[d performSelector:s3]; //输出:Animal running!
}
return 0;
}