动态多态

本文深入探讨了Objective-C中的动态多态,包括动态类型识别、动态绑定和动态加载。动态类型识别主要通过id类型实现,利用isa指针进行消息传递。类对象的方法链表和SEL、IMP类型在动态绑定中起关键作用。动态绑定确保消息直到运行时才与对应方法绑定,提高了灵活性。此外,文章还介绍了动态加载新类和方法的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

动态多态包括:

  1. 动态类型识别
  2. 动态绑定
  3. 动态加载

动态类型识别

@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即为SEL
for (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!"];
         }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值