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

2,644 阅读3分钟
原文链接: ppsheep.com

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

消息传递给其他对象

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

forwardingTargetForSelector:

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

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

#import "PPSMyObject.h"
@implementation PPSMyObject
- (void)logMyInfo{
    NSLog(@"myInfo");
}
@end

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

[self performSelector:@selector(logMyInfo)];

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

- (id)forwardingTargetForSelector:(SEL)aSelector{
    if (aSelector == @selector(logMyInfo)) {
        PPSMyObject *myObject = [[PPSMyObject alloc] init];
        return myObject;
    }
    NSLog(@"forwardingTargetForSelector");
    return [super forwardingTargetForSelector:aSelector];
}

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

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

methodSignatureForSelector: & forwardInvocation:

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

-(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封装了所有的该消息的实现细节,在此方法中实现方法

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

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

类方法的动态添加

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

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

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

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

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

+ (id)class
{
	return self;
}

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

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

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

/**
 处理类方法
 @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(@"我的动态类方法");
}

这样,就能够正常实现了

源代码同样的

github.com/yangqian111…