iOS AOP實戰

来源:https://www.cnblogs.com/lyjpost/archive/2019/08/25/11402024.html
-Advertisement-
Play Games

AOP: 面向切麵編程,偏向於處理業務的某個階段 適用場景: 1. 參數校驗:網路請求前的參數校驗,返回數據的格式校驗等等 2. 無痕埋點:統一處理埋點,降低代碼耦合度 3. 頁面統計:幫助統計頁面訪問量 4. 事務處理:攔截指定事件,添加觸發事件 5. 異常處理:發生異常時使用面向切麵的方式進行處 ...


AOP: 面向切麵編程,偏向於處理業務的某個階段

適用場景:

  1. 參數校驗:網路請求前的參數校驗,返回數據的格式校驗等等

  2. 無痕埋點:統一處理埋點,降低代碼耦合度

  3. 頁面統計:幫助統計頁面訪問量

  4. 事務處理:攔截指定事件,添加觸發事件

  5. 異常處理:發生異常時使用面向切麵的方式進行處理

  6. 熱修複:AOP可以讓我們在某方法執行前後或者直接替換為另一段代碼,我們可以根據這個思路,實現bug修複

  我們希望將以上需求分離到非業務邏輯的方法中,儘可能的不影響業務邏輯的代碼。

demo 從配置AOP到實際應用,有空給咱點個star~

源碼分析

  0. 類說明

 

 MDAspectInfo:作為對象,包含調用信息(NSInvocation)的對象
         作為協議,提供訪問對象的屬性  MDAspectIdentifier:包含一個hook的信息,調用者,時機,回調處理等
 MDAspectTracker:防止重覆hook  MDAspectsContainer:通過runtime給被hook的對象添加屬性,提供存儲和移除hook的方法  MDAspectToken:提供移除hook的協議

 

  1. hook時機

typedef NS_OPTIONS(NSUInteger, MDAspectOptions) {
    MDAspectPositionAfter   = 0,            /// 預設,當原方法執行完調用
    MDAspectPositionInstead = 1,            /// 替換原方法
    MDAspectPositionBefore  = 2,            /// 原方法執行前調用
    
    MDAspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.
};

  2. 配置文件

配置hook的類,hook時機,實例方法和類方法,以及回調處理

為了區分實例方法和類方法,需要在類方法前加一個“+”

+(NSDictionary *)AOP_MDViewControllerConfigDic{
    
    NSDictionary *configDic = @{
                                @"MDViewController":@{//hook那個類名
                                        @"TrackEvents":@[
                                                @{//實例方法
                                                    @"moment":@"before",//hook之前調用
                                                    @"EventSelectorName":@"instanceMethod",//實例方法名
                                                    @"block":^(id<MDAspectInfo>aspectInfo){//回調處理
                                                        // 獲取方法的參數
                                                        NSLog(@"跳轉");
                                                    },
                                                },
                                                @{//類方法
                                                    @"moment":@"instead",//替換原方法
                                                    @"EventSelectorName":@"+hookClassMethod",//類方法名
                                                    @"block":^(id<MDAspectInfo>aspectInfo){//回調處理
                                                        // 獲取方法的參數
                                                        NSLog(@"到處可以hook到我");
                                                    },
                                                },
                                            ]
                                        },
                                };
    return configDic;
}

  3. 解析管理類  

// hook到方法回調,完全控制
typedef void (^AspectEventBlock)(id<MDAspectInfo> aspectInfo);

@implementation MDAOPManager

+(void)load{ // 載入配置文件
    NSMutableDictionary *mutableDic = [NSMutableDictionary dictionary];
    [mutableDic addEntriesFromDictionary:[MDAOPManager AOP_MDViewControllerConfigDic]];
    [mutableDic addEntriesFromDictionary:[MDAOPManager AOP_MDSecViewControllerConfigDic]];
    [self configAOPWithDic:mutableDic];
    
}

+(void)configAOPWithDic:(NSDictionary *)configDic{
    // 解析配置文件
    for (NSString *className in configDic) {
        Class clazz = NSClassFromString(className);//拿到類名
        NSDictionary *config = configDic[className];//配置信息
        NSArray *trackArr = config[@"TrackEvents"];//方法數組
        if (trackArr) {
            for (NSDictionary *event in trackArr) {
                
                AspectEventBlock buttonBlock = event[@"block"];//回調
                NSString *method = event[@"EventSelectorName"];//方法名
                NSString *moment = event[@"moment"];//hook時機
                
                MDAspectOptions option = MDAspectPositionAfter;
                if ([moment isEqualToString:@"before"]) {
                    option = MDAspectPositionBefore;
                }else if ([moment isEqualToString:@"instead"]){
                    option = MDAspectPositionInstead;
                }
                
                SEL selector = NSSelectorFromString(method);

                if ([method hasPrefix:@"+"]) {//hook類方法
                    method = [method substringFromIndex:1];
                    selector = NSSelectorFromString(method);

                    [clazz aspect_hookClassSelector:selector withOptions:option usingBlock:^(id<MDAspectInfo> aspectInfo) {
                        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                            buttonBlock(aspectInfo);
                        });
                    } error:NULL];
                }else{//hook實例方法
                    
                    [clazz aspect_hookSelector:selector withOptions:option usingBlock:^(id<MDAspectInfo> aspectInfo) {
                        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                            buttonBlock(aspectInfo);
                        });
                    } error:NULL];
                }
            }
        }
    }
}

4. 對外介面

// 類直接調用,hook實例方法
+ (id<MDAspectToken>)aspect_hookSelector:(SEL)selector withOptions:(MDAspectOptions)options usingBlock:(id)block error:(NSError **)error;
// 對象調用,hook實例方法
- (id<MDAspectToken>)aspect_hookSelector:(SEL)selector withOptions:(MDAspectOptions)options usingBlock:(id)block error:(NSError **)error;
// 類直接調用,hook類方法
+ (id<MDAspectToken>)aspect_hookClassSelector:(SEL)selector withOptions:(MDAspectOptions)options usingBlock:(id)block error:(NSError *__autoreleasing *)error;

// 對象調用,hook類方法
- (id<MDAspectToken>)aspect_hookClassSelector:(SEL)selector withOptions:(MDAspectOptions)options usingBlock:(id)block error:(NSError *__autoreleasing *)error;

 

說明:MDAspect是對Aspects的擴展,添加了hook類方法的支持,希望能夠幫助大家~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • crtmpserver簡介 我們在第一章的時候已經簡要說明瞭crtmpserver,crtmpserver是一個由C++語言編寫的開源的RTMP流媒體伺服器,與其對應的商業產品自然是Adobe公司的FMS。與FMS相比,從功能上來說crtmpserver只能稱為FMS的簡化版本,其功能並沒有FMS那 ...
  • 在某處學習到瞭如何配置i3wm後,對其極感興趣。 學習到的經驗總結: Linux中的各種命令操作其實都要首先查閱 man command 或者 command -h 或者 command --help 這類的幫助命令。 i3寫好配置文件config後,執行 配置即刻生效。更多配置方法建議參考 htt ...
  • 本文包含作者工作中常用到的一些命令,用於診斷網路、磁碟占滿、fd泄漏等問題。命令包括ping、fping、tcpdump、lsof、netstat、/proc/$pid/fd、du、grep、traceroute、dig。 ...
  • Linux 系統中,存儲設主要有下麵幾種: DAS DAS 指 Direct Attached Storage,即直連附加存儲,這種設備直接連接到電腦主板匯流排上,電腦將其識別為一個塊設備,例如常見的硬碟,U 盤等,這種設備很難做到共用。 NAS NAS 指 Network Area Storag ...
  • MongoDB的一些高級語法 AND 和 OR操作 AND操作 OR操作 嵌入式文檔 插入 查詢 數組(Array)欄位 插入 查詢 聚合(Aggregation) 篩選數據 修改欄位 註意事項 包括現有欄位 取消_id欄位 排除欄位 分組操作 去重 分組操作運算 拆分數組 聯集合查詢 參考資料 M ...
  • 1.表與表之間的關係 2.為什麼要使用多張表 3.概念 4.分類 ANY關鍵字 ALL關鍵字 SOME關鍵字 IN關鍵字 ...
  • 一、簡述 截至到目前 (2019.04),HBase 有兩個主要的版本,分別是 1.x 和 2.x ,兩個版本的 Java API 有所不同,1.x 中某些方法在 2.x 中被標識為 過時。所以下麵關於 API 的樣例,我會分別給出 1.x 和 2.x 兩個版本。完整的代碼見本倉庫: + "Java ...
  • 安裝 第一步:打開網址,https://www.mysql.com,點擊downloads之後跳轉到https://www.mysql.com/downloads/選擇Community選項 第二步: 第一步結束後程式會跳轉到https://dev.mysql.com/downloads/網址,點擊 ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...