理解OC内部的消息调用、消息转发、类和对象-二

之前我们讲了关于OC消息转发,类和对象的内部实现的一些原理,现在我们接着讲,关于消息转发过程中的另外几个过程,将消息转发给其他对象处理,另外还有类方法的动态添加。

消息传递给其他对象

首先,我创建一个我自己的对象PPSMyObject,这个对象中有一个方法logMyInfo,然后我在我们的viewcontroller中来执行这个方法,当然VC里面是没有这个方法的,我肯定需要将这个方法传递给PPSMyObject来处理

forwardingTargetForSelector:

首先,我们在方法forwardingTargetForSelector:中来处理

PPSMyObject这个对象很简单,就只有一个方法logMyInfo,而且这个方法是在实现文件中,没有在头文件中声明,大家可以思考一下,消息转发为什么能够直接到实现文件中的方法呢?

1
2
3
4
5
6
7
8
9
10
#import "PPSMyObject.h"

@implementation PPSMyObject


- (void)logMyInfo{
NSLog(@"myInfo");
}

@end

然后在VC中,我们来执行消息转发,同样执行这个不存在的方法

1
[self performSelector:@selector(logMyInfo)];

然后在方法forwardingTargetForSelector:中,将这个方法抛给PPSMyObject来处理

1
2
3
4
5
6
7
8
- (id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(logMyInfo)) {
PPSMyObject *myObject = [[PPSMyObject alloc] init];
return myObject;
}
NSLog(@"forwardingTargetForSelector");
return [super forwardingTargetForSelector:aSelector];
}

执行后的效果,想想也应该清楚,程序没有崩溃,直接将这个消息传递给了PPSMyObject来处理

除了这一步,我们还有最后一步来处理

methodSignatureForSelector: & forwardInvocation:

通过这两个方法也能最后实现消息的转发

1
2
3
4
5
6
7
8
9
10
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSLog(@"methodSignatureForSelector");
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
if (!signature) {
if ([PPSMyObject instancesRespondToSelector:aSelector]) {
signature = [PPSMyObject instanceMethodSignatureForSelector:aSelector];
}
}
return signature;
}

在此方法中,找到如果PPSMyObject中能够找到方法aSelector,那么就将方法使用PPSMyObject签名

然后在方法forwardInvocation:中,NSInvocation封装了所有的该消息的实现细节,在此方法中实现方法

1
2
3
4
5
6
-(void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"forwardInvocation");
if ([PPSMyObject instancesRespondToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:[[PPSMyObject alloc] init]];
}
}

这样,我们就使用了两种方法,来实现消息的传递

类方法的动态添加

关于类方法的消息转发流程,我查了很久,但是目前也只是查到了在方法resolveClassMethod:中来处理,其他的转发流程我都没有找到,如果有同学了解的,请分享一下

我们之前说了一句,添加一个实例方法,其实是在类中增加一个方法,那么添加一个类方法,就应该是在元类中增加一个方法,因为我们之前讲了类对象其实是一个元类的实例,类比就能够理解到其中的原理

我们还是来看代码吧,一目了然

1
[[ViewController class] performSelector:@selector(logClassMethod)];

在类中,我执行一个类方法,在这里其实我们可以再聊一下类对象。在方法performSelector:,我们查一下这个其实是一个NSObject的实例方法,那么就说明[ViewController class]返回的是一个实例,我们再去Runtime的开源中看一下这个class方法,在Object.mm文件中这个方法是这样的

1
2
3
4
+ (id)class
{
return self;
}

返回的是自己 self 这里更是说明了ViewController其实是一个对象实例

好,回过头来,我们接着讲

调用了logClassMethod:方法,但是类中没有这个类方法,在resolveClassMethod:来动态增加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
处理类方法

@param sel 需要动态添加的方法 @return 是否已经有可实现的方法
*/
+(BOOL)resolveClassMethod:(SEL)sel{
Class metaClass = objc_getMetaClass(class_getName(self));
IMP imp = [self instanceMethodForSelector:@selector(myClassMethod)];
if (sel == @selector(logClassMethod)) {
class_addMethod(metaClass, sel,imp , "v@:");
return YES;
}
return [super resolveClassMethod:sel];
}

- (void)myClassMethod{
NSLog(@"我的动态类方法");
}

这样,就能够正常实现了

源代码同样的

https://github.com/yangqian111/Objective-C-Runtime

欢迎大家关注我的公众号,我会定期分享一些我在项目中遇到问题的解决办法和一些iOS实用的技巧,现阶段主要是整理出一些基础的知识记录下来

上边是公众号,下边是我个人微信

文章也会同步更新到我的博客:
http://ppsheep.com