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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...