iOS訊息轉發小記
訊息轉發流程圖
如果類接收到無法處理的訊息,會觸發訊息轉發機制,一共有三個步驟,接受者在每一步中均有機會處理訊息。步驟越往後,處理訊息的代價就越大,所以最好再第一步就處理完。
第一道防線
在類裡面實現兩個方法來處理未知訊息。執行動態方法解析之前,先會判斷是否曾經有動態解析。
-
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");
}
第三道防線
第三道防線有兩步
- 呼叫
methodSignatureForSelector
,獲取新的方法簽名(返回值型別,引數型別) - 呼叫
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 訊息轉發機制Demo解析iOS
- iOS進階之訊息轉發機制iOS
- iOS 訊息傳送與轉發詳解iOS
- iOS探索 動態方法解析和訊息轉發機制iOS
- iOS-訊息轉發和方法調配技術學習iOS
- iOS:利用訊息轉發機制實現多播委託iOS
- iOS探索:Runtime之訊息轉發及動態新增方法iOS
- 小碼哥iOS學習筆記第十三天:訊息傳送iOS筆記
- 使用 NSProxy 實現訊息轉發
- iOS 點選推送訊息跳轉指定介面 —總結篇iOS
- Objective-C中的訊息轉發Object
- 用程式碼理解 ObjC 中的傳送訊息和訊息轉發OBJ
- iOS開發小記-基礎篇iOS
- iOS開發 iOS整合FFmpeg及視訊格式轉碼iOS
- 小程式客服訊息
- 小程式 模版訊息
- Runtime底層原理探究(一) --- 訊息轉發機制(快速轉發)
- 小記:音訊格式轉化ByPython(下)音訊Python
- Objective-C Runtime (二):方法與訊息轉發Object
- iOS開發·runtime原理與實踐: 訊息轉發篇(Message Forwarding) (訊息機制,方法未實現+API不相容奔潰,模擬多繼承)iOSForwardAPI繼承
- RestCloud MQ訊息整合平臺,實現訊息自動記錄及重發RESTCloudMQ
- Runtime 從NullSafe原始碼看訊息轉發 機制Null原始碼
- 短視訊app開發之ios小視訊開發經驗共享APPiOS
- 小程式訊息推送訂閱
- 玩轉釘釘訊息推送!
- iOS開發常用小技巧記錄(持續更新)iOS
- iOS BLE 開發小記[1] CoreBluetooth 是什麼iOS
- iOS拍個小視訊iOS
- Android訊息框架速記Android框架
- uni-app技術分享| uni-app轉小程式-實時訊息APP
- Android系統開發小記:QQ微信視訊畫面方向旋轉Android
- IM撤回訊息-iOS客戶端實現iOS客戶端
- 一次訊息消費服務的記憶體洩漏排查小記記憶體
- uni-app小程式訊息推送APP
- 小程式傳送訂閱訊息
- iOS開發小tipiOS
- 用 Laravel 自帶訊息模組搭建小程式實時推送訊息Laravel