【记录】NSInvocation 的使用

【记录】NSInvocation 的使用,第1张

使用 invocationWithMethodSignature: 方法初始化一个 NSInvocation 实例

1、创建签名
	NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    if (signature == nil) {
        signature = [self methodSignatureForSelector:selector];
        if (signature == nil) { return nil; }
    }
2、创建 NSInvocation 实例
	NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
3、参数处理

参数的0和1位置分别被target和selector占用了,所以从位置2开始添加参数。

	if (invocation != nil) {
        [invocation setArgument:&wssMessage atIndex:2];
        [invocation invoke];
    }
4、返回值
	id res = nil;
	if (signature.methodReturnLength!=0) {
        [invocation getReturnValue:&res];
    }
5、示例代码

这里是其他博主分享的一个封装的代码,可以参考下。

6、关于替代 if…else 的一些小研究 6.1、NSInvocation方式

在视频交互的功能中需要处理接收的信令,原代码使用的if…else处理,消息处理方法显得很臃肿不易阅读。我做了优化,使用NSInvocation封装绑定消息和方法。

代码结构

// 接收消息
- (void)receiveMessage:(NSDictionary *)message
{
	...
	NSString *name = message[@"name"];
	NSDictionary *invocationDic = [self messageInvocationList];
    NSInvocation *invocation = invocationDic[name];
    if (invocation != nil) {
        [invocation setArgument:&wssMessage atIndex:2];
        [invocation invoke];
    }
}
// 消息执行方法列表
- (NSDictionary *)messageInvocationList
{
	return @{
		@"keyName1": [self invocationOfSelector:@selector(action1:)],
		@"keyName2": [self invocationOfSelector:@selector(action2:)],
		@"keyName3": [self invocationOfSelector:@selector(action3:)],
		...
	};
}
// 封装invocation
- (NSInvocation *)invocationOfSelector:(SEL)selector
{
    NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:selector];
    if (signature == nil) {
        signature = [self methodSignatureForSelector:selector];
        if (signature == nil) { return nil; }
    }
    
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
    return invocation;
}

...
// 处理消息的方法
- (void)action1:...{}
- (void)action2:...{}
- (void)action3:...{}
...

现在结构清晰多了,在list方法中一目了然,用到了哪些信令,在action方法可以清楚如何处理。也有朋友建议使用枚举和switch来处理,可以做到动态回调方法,不用生成和储存一个消息列表的实例对象。

6.2、subscribe

之前做WKWebView与前端js交互时封装过一个类,通过订阅的方式监听消息。

[webView subscripTo:KeyName messageHandler:^(WKScriptMessage * _Nonnull message) {
        // to do
    }];

也是生成了一个subscriptions字典实例来存储消息名和执行的block,收到消息调用对应消息的回调block。代码结构是这样的:

	// 1、描述信息
	[webView subscripTo:name1 messageHandler:^(WKScriptMessage * _Nonnull message) {
        // to do
    }];
    // 2、描述信息
    [webView subscripTo:name2 messageHandler:^(WKScriptMessage * _Nonnull message) {
        // to do
    }];
    // 3、描述信息
	[webView subscripTo:name3 messageHandler:^(WKScriptMessage * _Nonnull message) {
        // to do
    }];
    
    ...
    ...
    ...

我接手的项目里还有一个地方使用了大量的if…else,几百行的代码,看着就头疼。我也是采用了消息订阅的方式,虽然仍旧是很长的代码,但是结构清晰很多。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/996634.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存