iOS消息转发小记

简介: 消息转发流程图15277558865032.jpg如果类接收到无法处理的消息,会触发消息转发机制,一共有三个步骤,接受者在每一步中均有机会处理消息。

消息转发流程图

img_58f41d9c87a7b5c0c801e5cda7e8a6aa.jpe
15277558865032.jpg

如果类接收到无法处理的消息,会触发消息转发机制,一共有三个步骤,接受者在每一步中均有机会处理消息。步骤越往后,处理消息的代价就越大,所以最好再第一步就处理完。

第一道防线

在类里面实现两个方法来处理未知消息。执行动态方法解析之前,先会判断是否曾经有动态解析。

  • resolveInstanceMethod:处理实例方法
  • resolveClassMethod:处理类方法

我们来看个Demo,先看调用方代码

    TestA *testA = [[TestA alloc] init];
    [testA instanceMethod];
    [TestA classMethod];

再来看看TestA的定义。

// TestA.h
@interface TestA : NSObject

- (void)instanceMethod;
+ (void)classMethod;

@end

// TestA.m
@implementation TestA

- (void)newInstanceMethod {
    NSLog(@"newInstanceMethod");
}

+ (void)newClassMethod {
    NSLog(@"newClassMethod");
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(instanceMethod)) {
        // 动态添加方法newInstanceMethod
        Method method = class_getInstanceMethod([self class], @selector(newInstanceMethod));
        IMP imp = method_getImplementation(method);
        class_addMethod([self class], sel, imp, method_getTypeEncoding(method));
        // 成功处理,消息转发机制结束,调用newInstanceMethod
        return YES;
    }
    // 不能处理,进入第二步
    return [super resolveInstanceMethod:sel];
}

+ (BOOL)resolveClassMethod:(SEL)sel {
    if (sel == @selector(classMethod)) {
        // 动态添加方法newClassMethod
        Method method = class_getInstanceMethod(object_getClass(self), @selector(newClassMethod));
        IMP imp = method_getImplementation(method);
        class_addMethod(object_getClass(self), sel, imp, method_getTypeEncoding(method));
        // 成功处理,消息转发机制结束,调用newClassMethod
        return YES;
    }
    // 不能处理,进入第二步
    return [super resolveClassMethod:sel];
}

@end

TestA中头文件定义了两个方法,但是没有实现,如果不用消息转发机制处理异常,会导致crash,log想必大家应该很熟悉

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestA funcA]: unrecognized selector sent to instance 0x6040000125c0'

实例方法存储在类对象,类方法存储在元类对象,在调用class_addMethod时,第一个参数需要注意。

第二道防线

第二道防线依赖一个函数forwardingTargetForSelector

// 类方法
//+ (id)forwardingTargetForSelector:(SEL)aSelector {
//    
//}
- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (aSelector == @selector(instanceMethod)) {
        // 消息转发给TestB实例
        return [TestB new];
    }
    // 消息转发失败,进入下一步
    return nil;
}

// TestB.m
- (void)instanceMethod {
    NSLog(@"instanceMethod");
}

第三道防线

第三道防线有两步

  1. 调用methodSignatureForSelector,获取新的方法签名(返回值类型,参数类型)
  2. 调用forwardInvocation,转发消息,
// 方法签名(返回值类型,参数类型)
// 类方法减号改为加号
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature *signature = [TestB instanceMethodSignatureForSelector:aSelector];
    return signature;
}

// NSInvocation封装了方法调用,包括:方法调用者、方法名、方法参数
// anInvocation.target 消息接受者
// anInvocation.selector 函数名
// [anInvocation getArgument:NULL atIndex:0]; 获取参数
// 类方法减号改为加号
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    [anInvocation invokeWithTarget:[TestB new]];
}
目录
相关文章
|
iOS开发
iOS开发-聊天气泡的绘制和聊天消息列表
iOS开发-聊天气泡的绘制和聊天消息列表
213 0
iOS开发-聊天气泡的绘制和聊天消息列表
|
存储 缓存 开发者
iOS-底层原理 14:消息流程分析之 动态方法决议 & 消息转发
iOS-底层原理 14:消息流程分析之 动态方法决议 & 消息转发
300 0
iOS-底层原理 14:消息流程分析之 动态方法决议 & 消息转发
|
缓存 算法 C++
iOS-底层原理 13:消息流程分析之慢速查找
iOS-底层原理 13:消息流程分析之慢速查找
138 0
iOS-底层原理 13:消息流程分析之慢速查找
|
存储 缓存 自然语言处理
iOS-底层原理 12:消息流程分析之快速查找
iOS-底层原理 12:消息流程分析之快速查找
94 0
iOS-底层原理 12:消息流程分析之快速查找
|
搜索推荐 iOS开发
iOS小技能:消息推送扩展的使用
iOS小技能:消息推送扩展的使用
513 0
iOS小技能:消息推送扩展的使用
|
PHP 数据安全/隐私保护 iOS开发
分分钟搞定IOS远程消息推送(二)
分分钟搞定IOS远程消息推送
388 0
分分钟搞定IOS远程消息推送(二)
|
存储 Android开发 数据安全/隐私保护
分分钟搞定IOS远程消息推送(一)
分分钟搞定IOS远程消息推送
219 0
分分钟搞定IOS远程消息推送(一)
|
Android开发 数据安全/隐私保护 iOS开发
APNS IOS 消息推送
一.Apns简介: Apns是苹果推送通知服务。 二.原理: APNs会对用户进行物理连接认证,和设备令牌认证(简言之就是苹果的服务器检查设备里的证书以确定其为苹果设备);然后,将服务器的信息接收并且保存在APNs当中,APNs从其中注册的列表中查找该IOS设备(设备可以为iPhone、iPad、iPod Touch,版本是iOS3.
1682 0
|
iOS开发
APNS IOS 消息推送处理失效的Token
在开发苹果推送服务时候,要合理的控制ios设备的Token,而这个Token是由苹果服务器Apns产生的,就是每次app问Apns要Token,由苹果服务器产生的Token会记录到Apns里面,我们需要根据该Token进行制定设备的消息推送,所有Token需要我们自己去记录和管理,每个设备对应唯一的Token,而app的用户登录会有自己约束的别名,与该tokne进行关系绑定,这样按该别名进行推送,就可以找到对应的Token,进而推送到该iso设备上,对应失效的Token我们需要访问苹果的feedbackServer,拿取失效的Token,然后把本地记录的失效token进行移除。
2006 0