首页 > 学院 > 开发设计 > 正文

动态多态

2019-11-06 07:45:57
字体:
来源:转载
供稿:网友

多态:相同接口,不同实现 相同接口:方法的签名、参数、返回值相同 不同实现:具体实现的内容不同

动态多态包括:

动态类型识别动态绑定动态加载

动态类型识别

@interface A:NSObject-(void)draw;@end@interface B:A-(void)draw;@end@interface C:B-(void)draw;@end@interface D:NSObject-(void)paint:(A*)aA;//此处可改为//-(void)paint:(id)aA@end@implementation D-(void)paint:(A*)aA//此处可改为//-(void)paint:(id)aA{[aA draw];}@end@autoreleasepool{D *d = [[D alloc] init];A *a = [[D alloc] init];B *b = [[D alloc] init];C *c = [[D alloc] init];[d paint:a];[d paint:b];[d paint:c];//因为b,c对象都继承于A类,故在此可以用父类指针调用子类对象

id类型和多态的识别原理

而这里如果改成id指针类型,其不进行类型检查,可以指向属于任何类的对象,因为id类型不能说明对象的类型,而是要求对象本身提供这些信息isa实例变量永远是对象的第一个实例对象, 而id指针相当于class *isa 指针,其中包含了可以储存对象各种信息的地址,在信息的传递过程中充当一个“桥梁”的作用。id指针的信息传递过程就是从子类开始,一个一个往上一级寻找是否有匹配的信息,把对象和类对象匹配起来,从而实现消息的传递过程。 isa的消息传递

类对象的方法链表

struct objc_method{ SEL method_name;//方法ID char* method_types;//方法类型(返回值、参数) IMP method_imp;//方法地址(IMP)函数调用

SEL IMP类型的作用和特点

SEL类型:selector,方法签名相同则ID相同,与类无关IMP类型:implementation, 是一个指针类型,寻找到函数过后的函数调用,返回一个id typedef id(*IMP)(id, SEL,...)@autoreleasepool{Person *a = [[Person alloc] init];[a PRint];SEL act = @selector("print");//act得到print的SEL//或者 SEL act = NSSelectorFromString(@"print");从字符串获得方法的SEL//或者NSSring * name = NSStringFromSelector(act);从const char * sn = sel_getName(act);//用SEL做参数,找到指定的方法,并取得其首地址a.name = @"tom";NSLog(@"%s",sn);IMP p = [a methodForSelector:act];p(a, act);//p就相当于*IMP【typedef id(*IMP)】(id, SEL,...),a相当于self,act即为SELfor (int i=0; i<10000; i++){ //[a print]; p(a, act); }//在循环次数很多的情况下,如果用第一种方法,消息传递的方法名寻找过程很耗费时间,所以如果改进为第二种方法,可以节省很多时间}

动态类型识别的常用方法

如何得到类对象

Class rectClass=[Rectangle class];//通过类名得到类对象Class aClass=[anObject class];//通过实例得到类对象if([obj1 class] == [obj2 class])//两个类对象是否为同类

类(对象)和字符串

Class someClass = NSClassFromString(@"NSView");id object = [[someClass alloc]init];//从字符串得到类对象NSString *view = NSStringFromClass([NSView class]);NSString *className = NSStringFromClass([anObject class]}//从类或者类对象得到类名的字符串

判定与应用

判定类与成员

class-object类对象的写法:[类名或者对象名 class]

-(BOOL)isKindOf:class-object//对象是不是class-object或者其子类的成员-(BOOL)isMemberOfClass:class-object//对像是不是class-object的成员if([object isMemberOf:[someClass class]])//判定是否为某个类的实例对象+(BOOL)isSubclassOfClass:class-object//对象是指定类的子类吗

是否响应

等号右边selector的写法:@selector(方法名、@“字符串”)

-(BOOL)respondToSelector:selector//对象是否能响应selector所指定的方法+(BOOL)instancesRespondToSelector:selector//指定的类对象是否能响应selector

应用

-(id)performSelector:selector//应用selector指定的方法-(id)performSelector:selector withObject:object//应用selector指定的方法,传递参数object1-(id)performSelector:selector withObject:object withObject:object2//应用selector指定的方法,传递参数object1,传递参数object2..........

静态/动态类型识别的区别

静态多态编译之前就提供了对象信息,编译时可以检查(对象和类是否匹配,对象是否拥有指定的方法等)动态多态是在编译时才确定对象信息,动态多态要求方法签名、返回值、参数类型完全一致如果不涉及到多态,尽量使用静态类型

动态绑定

消息派发:oc中消息一直到运行时才能绑定到对应的方法

[receiver message];转换成函数 objc_msgSend(receiver, selector); 其中receivier赋值给self, selector就是方法选择器

如果消息是 [super message]; 这里写图片描述 为了加快消息处理,运行时会缓存映射表,在每个类中查找方法会先在缓存中找,如果找不到再到方法映射表中去找

动态加载

oc允许在运行时加载一个新类,或给已有的类加载新的方法 只需要四步 1. #import 《objc/runtime.h> 2. 为class pair分配空间 3. 增加方法(class_addMethod)或者实例变量(class_addlvar) 4. 注册新类

#import<objc/runtime.h>//注意引入void sayHello(id self,SEL_cnd,NSString* aHello){ NSLog(@"%@",aHello);}//-(void)sayHello:(NSString*)aHello;上面函数就时这个方法的等价写法//void(*)(id self, SEL_cnd,NSString*);可以看出每个方法都有self和SEL两个隐含参数@autoreleasepool{ Class parentClass=[NSObject class]; Class newClass=objc_allocateClassPair(parentClass,"ASNewClass",0);//为class pair分配空间 Class_addMethod(newClass,@selector(sayHello:),(IMP)sayHello,"v@:@"); //增加方法(class_addMethod)或者实例变量(class_addlvar) objc_registerClassPair(newClass);//注册新类 id p = [[newClass alloc] init]; if([p respondsToSelector:@selector(sayHello:)]){ [p performSelector:@selector(sayHello:) withObject:@"hello world!"]; } }
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表