iOS消息机制--动态方法解析、消息转发机制
来源:互联网 发布:linux下python mmap 编辑:程序博客网 时间:2024/05/19 03:41
动态方法解析:
对象在收到无法解读的消息后,调用类方法+ (BOOL)resolveInstanceMethod:(SEL)sel来动态为其新增实例方法以处理该选择子。(如果尚未实现的方法是类方法,则调用+ (BOOL)resolveClassMethod:(SEL)sel)
新建HTResolveMethod类
①HTResolveMethod.h
#import <Foundation/Foundation.h>@interface HTResolveMethod : NSObject@property (nonatomic, copy) NSString *name;@end
②HTResolveMethod.m
#import "HTResolveMethod.h"#import <objc/runtime.h>@implementation HTResolveMethod@dynamic name;/** * 第一步:动态方法解析,征询接收者,看其是否能动态添加方法,来处理当前这个未知的选择子 * 为name动态添加set和get方法 */+ (BOOL)resolveInstanceMethod:(SEL)sel { NSString *selectorStr = NSStringFromSelector(sel); /** * i(类型为int) * v(类型为void) * @(类型为id) * :(类型为SEL) */ if ([selectorStr isEqualToString:@"setName:"]) { class_addMethod(self, sel, (IMP)autoDictionarySetter, "v@:@"); } else if ([selectorStr isEqualToString:@"name"]) { class_addMethod(self, sel, (IMP)autoDictionaryGetter, "@@:"); } return [super resolveInstanceMethod:sel];}void autoDictionarySetter(id self,SEL _cmd,id value) { NSLog(@"name的set方法==%@",value);}id autoDictionaryGetter(id self,SEL _cmd) { return @"name的get方法";}@end
③在ViewController.m中调用
HTResolveMethod *resolveMethod = [[HTResolveMethod alloc] init];resolveMethod.crashDelegate = self;resolveMethod.name = @"颖宝";NSLog(@"%@",resolveMethod.name);
重定向(备援接收者)
当不能在+ (BOOL)resolveInstanceMethod:(SEL)sel中动态添加方法处理选择子时,当前接收者还有一次机会处理未知的选择子。可以在- (id)forwardingTargetForSelector:(SEL)aSelector中把这条消息转给其他接收者来处理。
新建HTResolveMethod类
①HTResolveMethod.h
#import <Foundation/Foundation.h>@interface HTResolveMethod : NSObject- (void)setupDatasWithTitle:(NSString *)title;@end
②HTResolveMethod.m
#import "HTResolveMethod.h"#import "HTForwardingTarget.h"@implementation HTResolveMethod/** * 第二歩:进入消息转发流程重定向 * 将setupDatasWithTitle:转发到HTForwardingTarget类 */- (id)forwardingTargetForSelector:(SEL)aSelector { NSString *selectorStr = NSStringFromSelector(aSelector); if ([selectorStr isEqualToString:@"setupDatasWithTitle:"]) { HTForwardingTarget *forwardingTarget = [HTForwardingTarget new]; return forwardingTarget; } return [super forwardingTargetForSelector:aSelector];}@end
新建HTForwardingTarget类
③HTForwardingTarget.m
- (void)setupDatasWithTitle:(NSString *)title { NSLog(@"重定向成功了,%@",title);}
④在ViewController.m中调用以下方法
HTResolveMethod *resolveMethod = [[HTResolveMethod alloc] init];[resolveMethod setupDatasWithTitle:@"我的日记"];
完整的消息转发
如果备援接收能未能处理选择子,会调用- (NSMethodSignature )methodSignatureForSelector:(SEL)aSelector生成方法签名,然后系统用这个方法签名生成NSInvocation对象。NSInvocation对象包含选择子、目标及参数。之后调用- (void)forwardInvocation:(NSInvocation )anInvocation方法改变调用目标,使消息在新目标上得以调用。这种方法有两种实现方式:一种实现方式与调用备援接收者方法有异曲同工的作用,而越往后面处理消息的代价就越大,所以不推荐在此方法中实现类似效果。另一种实现方式是改变消息内容或是改变选择子。
新建HTResolveMethod类
①HTResolveMethod.h
#import <Foundation/Foundation.h>@interface HTResolveMethod : NSObject- (void)setupDatasWithTitle:(NSString *)title;@end
②HTResolveMethod.m
#import "HTResolveMethod.h"#import "HTForwardingTarget.h"@implementation HTResolveMethod/** * 第二歩:进入消息转发流程重定向 * 将setupDatasWithTitle:转发到HTForwardingTarget类 */- (id)forwardingTargetForSelector:(SEL)aSelector { NSString *selectorStr = NSStringFromSelector(aSelector); if ([selectorStr isEqualToString:@"setupDatasWithTitle:"]) { HTForwardingTarget *forwardingTarget = [HTForwardingTarget new]; return forwardingTarget; } return [super forwardingTargetForSelector:aSelector];}@end
新建HTForwardingTarget类
③HTForwardingTarget.m
//第三步,生成方法签名,然后系统用这个方法签名生成NSInvocation对象- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSString *selectedStr = NSStringFromSelector(aSelector); if ([selectedStr isEqualToString:@"setupDatasWithTitle:"]) { NSMethodSignature *sign = [NSMethodSignature signatureWithObjCTypes:"v@:@"]; return sign; } return [super methodSignatureForSelector:aSelector];}//第四步,改变选择子- (void)forwardInvocation:(NSInvocation *)anInvocation { HTForwardInvocation *forwardInvocation = [[HTForwardInvocation alloc] init]; anInvocation.selector = NSSelectorFromString(@"setMsg:"); if ([forwardInvocation respondsToSelector:[anInvocation selector]]) { [anInvocation invokeWithTarget:forwardInvocation]; } else { [super forwardInvocation:anInvocation]; }}
新建HTForwardInvocation类
④HTForwardInvocation.m
- (void)setMsg:(NSString *)msg { NSLog(@"选择子被改变了,%@",msg);}
⑤在ViewController.m中调用以下内容
HTResolveMethod *resolveMethod = [[HTResolveMethod alloc] init];[resolveMethod setupDatasWithTitle:@"我的日记"];
如果最终方法仍未实现,则调用NSObject的- (void)doesNotRecognizeSelector:(SEL)aSelector方法抛出异常
那么问题来了,知道动态方法解析、消息转发机制有什么用呢?我们举个简单的小例子:
新建HTResolveMethod类
①HTResolveMethod.h
#import <Foundation/Foundation.h>/** 声明协议,当HTResolveMethod或其子类自定义方法未实现时,保证程序不崩溃 ,弹出提示框,并在控制台输出未实现的方法*/@protocol ResolveMethodCrashDelegate <NSObject>- (void)resolveMethodCrashWithSelName:(NSString *)selName;@end@interface HTResolveMethod : NSObject@property (nonatomic, weak) id<ResolveMethodCrashDelegate> crashDelegate;@end
②HTResolveMethod.m
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature *sign = [NSMethodSignature signatureWithObjCTypes:"v@:"]; return sign;}- (void)forwardInvocation:(NSInvocation *)anInvocation { [super forwardInvocation:anInvocation];}- (void)doesNotRecognizeSelector:(SEL)aSelector { NSString *selectedStr = NSStringFromSelector(aSelector); [self crashHandle:selectedStr];}- (void)crashHandle:(NSString *)selName { if (self.crashDelegate && [self.crashDelegate respondsToSelector:@selector(resolveMethodCrashWithSelName:)]) { [self.crashDelegate resolveMethodCrashWithSelName:selName]; }}
新建HTResolveSonMethod类(只声明不实现)
③HTResolveSonMethod.h
#import "HTResolveMethod.h"@interface HTResolveSonMethod : HTResolveMethod- (void)tapNextButtonWithTag:(NSInteger)tag;@end
④ViewController.m中调用以下方法
#import "ViewController.h"#import "HTResolveSonMethod.h"@interface ViewController ()<ResolveMethodCrashDelegate>@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor purpleColor]; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(30, 100, CGRectGetWidth(self.view.bounds)-60, 30); [button setTitle:@"准备崩溃" forState:UIControlStateNormal]; [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button];}- (void)buttonClick:(id)sender { HTResolveSonMethod *resolveSonMethod = [[HTResolveSonMethod alloc] init]; resolveSonMethod.crashDelegate = self; [resolveSonMethod tapNextButtonWithTag:4];}#pragma ResolveMethodCrashDelegate- (void)resolveMethodCrashWithSelName:(NSString *)selName { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示信息" message:[NSString stringWithFormat:@"崩溃方法:%@",selName] preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]; [alertController addAction:cancelAction]; [self presentViewController:alertController animated:YES completion:nil]; NSLog(@"此方法不存在selName==%@",selName);}@end
效果如图:
demo地址
- iOS消息机制--动态方法解析、消息转发机制
- IOS消息转发机制
- iOS消息转发机制
- ios消息转发机制
- IOS 消息转发机制
- iOS消息转发机制
- iOS消息转发机制
- ios 消息转发机制
- ios-消息转发机制
- iOS 消息转发机制Demo解析
- 动态消息转发机制实例
- Ios的消息转发机制
- iOS消息转发机制详解
- IOS消息传递转发机制
- iOS的消息转发机制
- Runtime(二)动态添加方法以及消息转发机制
- 消息转发机制与Aspects源码解析
- 消息转发机制与Aspects源码解析
- 51nod 1478 括号序列的最长合法子段(栈-括号匹配寻找最长合法子串长度及其个数)
- 转载:移动前端开发之viewport的深入理解
- 文章标题
- go提问模板
- JPEG编码中的DCT与量化
- iOS消息机制--动态方法解析、消息转发机制
- Codeforces Round #404 (Div. 2) D. Anton and School
- 【并发】volatile详解
- xampp mysql无法启动。
- Eclipse GitHub SSH2 key配置
- 使用IDEA创建一个Spring Boot项目
- Flask-heroku部署相关问题
- string类的用法
- 摄像机