Runtime消息动态解析与转发流程
先上圖:
?
下面根據具體代碼看這張圖。
一、創建一個Person類,
?Person.h
#import <Foundation/Foundation.h>@interface Person : NSObject-(void)sendMessage:(NSString *)message;@endPerson.m
#import "Person.h" #import <objc/runtime.h>@implementation Person@end大家可以看到,Person類只聲明了 sendMessage:方法,在.m文件里沒有實現這個方法。
?
這時,如果在viewController中調用Person類的sendMessage方法,程序會發生崩潰。
#import "ViewController.h" #import "Person.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];[[[Person alloc]init] sendMessage:@"Hello"];}?
?
結合上面的圖片,我們說說消息處理的機制。
1.當我們調用的方法沒有具體的實現時,會調用
+ (BOOL)resolveInstanceMethod:(SEL)sel;
+(BOOL)resolveInstanceMethod:(SEL)sel{NSString *methodName = NSStringFromSelector(sel);if ([methodName isEqualToString:@"sendMessage:"]) {//我們可以在這里添加方法的實現return class_addMethod(self, sel, (IMP)sendMessage, "v@:@");}return NO;}void sendMessage (id self, SEL _cmd, NSString *message){NSLog(@"message=%@",message); }BOOL class_addMethod(Class cls, SEL name, IMP imp,?const char *types):為類動態添加方法。如果有同名會返回NO,成功返回YES。
其中的參數types查詢地址:(v:表示void, @:表示類型,等等)
?
2. 如果?resolveInstanceMethod:方法返回NO,調用
-(id)forwardingTargetForSelector:(SEL)aSelector;
這個方法是找備用者,比如:Animal類。
Animal.h
#import <Foundation/Foundation.h>@interface Animal : NSObject@endAnimal.m
#import "Animal.h"@implementation Animal-(void)sendMessage:(NSString *)message{NSLog(@"message=%@",message); }@endAnimal類沒有聲明sendMessage:方法,但在.m文件里有這個方法的實現,可以作為備用者。如下:
-(id)forwardingTargetForSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);if ([methodName isEqualToString:@"sendMessage:"]) {if ([[Animal new] respondsToSelector:aSelector]) {return [Animal new];}}return [super forwardingTargetForSelector:aSelector]; }3. 如果?forwardingTargetForSelector:(SEL)aSelector返回 nil。
// 若前兩種方法都不處理,則走這里 // 1)方法簽名 -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);if ([methodName isEqualToString:@"sendMessage:"]) {return [NSMethodSignature signatureWithObjCTypes:"v@:@"];}return [super methodSignatureForSelector:aSelector]; } // 2) 簽名后,消息轉發,找備用者 -(void)forwardInvocation:(NSInvocation *)anInvocation{SEL selector = [anInvocation selector];Animal *animal = [Animal new];if ([animal respondsToSelector:selector]) {[anInvocation invokeWithTarget:animal];} else{[super forwardInvocation:anInvocation];} }?
4.如果走到第3步,仍然不做處理,如下:
-(void)forwardInvocation:(NSInvocation *)anInvocation{[super forwardInvocation:anInvocation]; }這時為了程序的健壯性,防止崩潰,可以用以下方法處理。
// 若前3方法都不處理,為了防止崩潰,可調用此方法 -(void)doesNotRecognizeSelector:(SEL)aSelector{NSString *methodName = NSStringFromSelector(aSelector);NSLog(@"找不到 %@ 這個方法的實現",methodName); }?
附加源碼
轉載于:https://www.cnblogs.com/lfyDragon/p/9177710.html
總結
以上是生活随笔為你收集整理的Runtime消息动态解析与转发流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中科大EPC课程爬取
- 下一篇: 初识设计模式(装饰者模式)