使用 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,几百行的代码,看着就头疼。我也是采用了消息订阅的方式,虽然仍旧是很长的代码,但是结构清晰很多。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)