在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
上面主要介绍了下<objc/message.h>一些基础,运行时还包括<objc/runtime.h>,这个类的作用和C#、Java的反射有些类似。也是获取类名、属性、方法等。之前的属性关联就是利用该类中的方法。在网上也找了下一些博客,发现http://blog.csdn.net/a19860903/article/details/45044701中写的蛮详细的,可以参考来看。