在C#、Java中有编译时多态和运行时多态,在OC中,只有运行时的多态,这与它的运行机制有关。OC中,方法的调用是通过消息的传递来进行的。在IOS runtime动态运行时一http://www.cnblogs.com/5ishare/p/4708647.html中主要大致介绍了下运行时的过程,这篇主要看下消息转发(实现多态的基础)。
一.引入
在<objc/objc-runtime.h>中有两个.h,<objc/runtime.h>和<objc/message.h>,这篇主要了解<objc/message.h>
二.消息转发
在该类中主要有3中方法 (其他几种我也不知道所以有3种):objc_msgSend、objc_msgSendSuper、method_invoke。
像objc_msgSend_stret、objc_msgSend_fpret函数返回结构体、浮点数这些需要经过CPU特殊处理,所以不用太留意。它们就是上面3种的变体,当返回的是结构体、浮点数时,会调用 _stret、_fpret这些。
三.方法的使用
在使用之前有几个注意点:
1.要引入框架<objc/objc-runtime.h>
2.直接写入运行时代码会报错需要按下图设置一下
1).objc_msgSend
在IOS runtime动态运行时一博客中也写了oc中方法调用其实是转为objc_msgSend来实现消息转发。
2).objc_msgSendSuper
这个是将消息转发给父类。方法的第一个参数是一个objc_super类型的结构体。结构体主要包括两个变量:
1.receiver:即消息的实际接收者
2.superClass:指针当前类的父类
struct objc_super { /// Specifies an instance of a class. __unsafe_unretained id receiver; /// Specifies the particular superclass of the instance to message. __unsafe_unretained Class super_class; };
id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
3).method_invoke
在C#多线程中有invoke,这里和C#类似,用于方法的调用。这里需要传结构体Method。可以通过runtime.h来获得类中的某个Method
method_invoke(id receiver, Method m, ...)
四、测试结果
在项目中创建了一个Father类和一个继承Father的Son。Son类重写了父类的-(NSString *)getNameWithfamily:(NSString *)family方法。
#import <Foundation/Foundation.h> @interface Father : NSObject -(NSString *)getNameWithfamily:(NSString *)family; @end
// // Father.m // RunTime // // Created by City--Online on 15/11/24. // Copyright © 2015年 City--Online. All rights reserved. // #import "Father.h" @implementation Father -(NSString *)getNameWithfamily:(NSString *)family; { return [NSString stringWithFormat:@"Father %@",family]; } @end
// // Son.h // RunTime // // Created by City--Online on 15/11/24. // Copyright © 2015年 City--Online. All rights reserved. // #import "Father.h" @interface Son : Father @end
// // Son.m // RunTime // // Created by City--Online on 15/11/24. // Copyright © 2015年 City--Online. All rights reserved. // #import "Son.h" @implementation Son -(NSString*)getNameWithfamily:(NSString *)family { return [NSString stringWithFormat:@"Son %@",family]; } @end
1.objc_msgSend 通过objc_msgSend调用son的getNameWithfamily:方法 返回为字符串、一个参数
Son *son=[[Son alloc]init]; NSString *name= objc_msgSend(son, @selector(getNameWithfamily:),@"Tom"); NSLog(@"%@",name);
2015-11-24 13:44:26.705 RunTime[6514:223611] Son Tom
2.objc_msgSendSuper 通过objc_msgSendSuper调用父类的方法类似[super xxxxx],主要是第一个objc_super类型的结构体.
struct objc_super objcsuper; objcsuper.receiver=father; objcsuper.super_class=[son superclass]; NSString *superName=objc_msgSendSuper(&objcsuper, @selector(getNameWithfamily:),@"Cui"); NSLog(@"%@",superName);
2015-11-24 13:44:26.705 RunTime[6514:223611] Father Cui
3.method_invoke
Method method= class_getInstanceMethod([Son class], @selector(getNameWithfamily:)); NSString *invokeName= method_invoke(son,method,@"Zhao"); NSLog(@"%@",invokeName);
2015-11-24 13:44:26.705 RunTime[6514:223611] Son Zhao
Method method= class_getInstanceMethod([father class], @selector(getNameWithfamily:)); NSString *invokeName= method_invoke(father,method,@"Zhao"); NSLog(@"%@",invokeName);
2015-11-24 13:51:28.288 RunTime[6546:231306] Father Zhao