国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Objective-C 消息轉發機制

2019-11-07 23:11:54
字體:
來源:轉載
供稿:網友

一圖勝千言,習慣性的先來一張圖以便對消息轉發有個整體的把握

運行時系統庫方法查詢流程圖

運行時系統庫方法查詢

對于對象無法處理的消息,如果不做轉發處理的話,程序最終會調用NSObjective的doesNotRecognizeSelector:消息將程序crash掉。

Objective-C提供了兩種消息轉發選項

快速轉發:NSObject類的子類A可以通過重寫NSObject類的forwardingTargetForSelector:方法,將A的實例無法識別的消息轉發給目標對象B,從而實現快速轉發。該技巧就像是將對象的實現代碼與轉發對象合并到一起。這類似于實現的多繼承行為。如果你有一個定了對象 能夠消化哪些消息的目標類,這個技巧可以取得很好的效果標準(完整)轉發:NSObject類的子類A可以通過重寫NSObject類的forwardInvocation:方法,實現標準轉發。該技巧可以通過methodSignatureForSelector:方法獲取一個NSInvocation對象,能獲取消息的全部內容(包含目標,方法名,和參數)。

如果你擁有了一個定義了對象能夠消化哪些消息的目標類,快速轉發可以取得很好的效果。如果你沒有這樣目標類或想要執行其他處理過程(如記錄日志并‘吞下’消息),就應該使用完整轉發。

寫了一大推字感覺很抽象,下面來點干貨

下面我要把Test實例的logName消息轉發給Target實例,代碼如下 Test頭文件

//// Test.h// ForwardMsg//// Created by 孫磊 on 2017/2/25.// Copyright ? 2017年 孫磊. All rights reserved.//#import <Foundation/Foundation.h>@interface Test : NSObject-(void)logName;@end

Test實現文件

//// Test.m// ForwardMsg//// Created by 孫磊 on 2017/2/25.// Copyright ? 2017年 孫磊. All rights reserved.//#import "Test.h"#import "Target.h"#import <objc/runtime.h>@implementation Test{ Target *mTarget;}- (instancetype)init{ self = [super init]; if (self) { //創建目標對象 mTarget = [Target new]; } return self;}#if 0//當一個對象無法識別消息后,會執行resolveInstanceMethod或者resolveClassMethod方法//如果不想進行消息轉發,可以在此方法中動態添加消息來做處理//如果不重寫此方法或者此方法返回NO,系統會執行forwardingTargetForSelector進行快速轉發+ (BOOL)resolveInstanceMethod:(SEL)sel{ if(sel == @selector(logName)){ //第四個參數詳解地址 https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html //v代表返回類型為void //@代表一個對象 //:代表一個selector //因為OC中的每個方法都有默認的兩個參數sel 和 selector,所以一般都是v@: class_addMethod([self class],sel,(IMP)dynamicMethodIMP,"v@:"); return YES; } return [super resolveInstanceMethod:sel];}//萬年備胎void dynamicMethodIMP(id self, SEL _cmd){ //對無法識別的消息做處理 NSLog(@"該對象無法識別 %@ 方法------%s", NSStringFromSelector(_cmd),__func__);}#else /***************==========1、快速消息轉發,快速轉發只可以獲取到方法簽名==========*******************/-(id)forwardingTargetForSelector:(SEL)aSelector{ NSLog(@"%s",__func__); if ([mTarget respondsToSelector:aSelector]) { //目標對象有對應的處理方法,則就會快速消息轉發,不會再執行完整消息轉發了 return mTarget; } //目標對象也沒有對應的方法,此時系統會執行forwardInvocation進行完整消息轉發 return nil;}/***********=============2、標準(完整)消息轉發,完整消息轉發,可以獲取方法簽名,參數等詳細信息==========*********///返回一個完整的方法簽名,提供給forwardInvocation以便完整轉發消息-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{ NSMethodSignature* signature = [super methodSignatureForSelector:aSelector]; if (!signature) signature = [mTarget methodSignatureForSelector:aSelector]; return signature;}-(void)forwardInvocation:(NSInvocation *)anInvocation{ NSLog(@"%s-----完整消息轉發------",__func__); SEL invSEL = anInvocation.selector; if ([mTarget respondsToSelector:invSEL]){ //利用forwardInvocation方法來重新指定消息處理對象 [anInvocation invokeWithTarget:mTarget]; } else { [self doesNotRecognizeSelector:invSEL]; }}#endif@end

目標文件的頭文件

//// Target.h// ForwardMsg//// Created by 孫磊 on 2017/2/25.// Copyright ? 2017年 孫磊. All rights reserved.//#import <Foundation/Foundation.h>@interface Target : NSObject-(void)logName;@end

目標文件的實現文件

//// Target.m// ForwardMsg//// Created by 孫磊 on 2017/2/25.// Copyright ? 2017年 孫磊. All rights reserved.//#import "Target.h"@implementation Target-(void)logName{ NSLog(@"我是備用方法---%s",__func__);}@end

推薦一個國外大大利用消息轉發避免后臺返回null或者NSNull而引起的奔潰問題,用法也很簡單,直接把NullSafe.m拖到項目中即可,該文件會在運行時自動加載


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乌兰县| 阿尔山市| 闽侯县| 五家渠市| 灵璧县| 文安县| 台东县| 丹东市| 垫江县| 乐都县| 朝阳区| 鸡东县| 龙井市| 梓潼县| 喀喇沁旗| 区。| 许昌县| 麦盖提县| 包头市| 林芝县| 南汇区| 瑞丽市| 磐安县| 衡水市| 松原市| 分宜县| 北川| 镇江市| 梁平县| 华池县| 盘山县| 海安县| 肇源县| 襄垣县| 乌恰县| 长武县| 河北省| 芮城县| 五莲县| 南漳县| 盐池县|