首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Objective-C AOP 編程實戰:基於 Runtime 消息轉發的攔截器實現

     編輯:關於C語言

Objective-C AOP 編程實戰:基於 Runtime 消息轉發的攔截器實現

AOP(面向切面編程)將日誌、性能統計、權限檢查等**橫切關注點**從業務邏輯中剝離。Objective-C 強大的 Runtime 機制(動態方法解析、消息轉發)使 AOP 實現極其優雅。本文展示一個生產級攔截器 XYAOP 的核心原理與使用姿勢。

核心概念

  • 切面:橫切多個類/方法的通用邏輯(如日誌)
  • 切點:具體攔截的方法(如 -sumA:andB:)
  • 通知:在切點前/後/異常執行的代碼塊

使用示例:攔截 sumA:andB:

- (void)clickTestAop:(id)sender {
    AopTestM *test = [[AopTestM alloc] init];
    NSLog(@"run1");
    [test sumA:1 andB:2];  // 原始調用:輸出 sum=3
    
    // 前置通知:修改參數為 3、4
    NSString *before = [XYAOP interceptClass:[AopTestM class] 
                         beforeExecutingSelector:@selector(sumA:andB:) 
                                        usingBlock:^(NSInvocation *inv) {
        int a = 3, b = 4;
        [inv setArgument:&a atIndex:2];  // 索引 0=self, 1=_cmd, 2=第一個參數
        [inv setArgument:&b atIndex:3];
        NSLog(@"before: a=%d, b=%d", a, b);
    }];
    
    // 後置通知:獲取參數與返回值
    NSString *after = [XYAOP interceptClass:[AopTestM class] 
                       afterExecutingSelector:@selector(sumA:andB:) 
                                      usingBlock:^(NSInvocation *inv) {
        int a, b; NSString *ret;
        [inv getArgument:&a atIndex:2];
        [inv getArgument:&b atIndex:3];
        [inv getReturnValue:&ret];
        NSLog(@"after: a=%d, b=%d, ret=%@", a, b, ret);
    }];
    
    NSLog(@"run2");
    [test sumA:1 andB:2];  // 觸發攔截:輸出 before→sum=7→after
    
    [XYAOP removeInterceptorWithIdentifier:before];
    [XYAOP removeInterceptorWithIdentifier:after];
    NSLog(@"run3");
    [test sumA:1 andB:2];  // 移除後恢復原始:出 sum=3
}

運行輸出

run1
fun running. sum : 3
run2
before: a=3, b=4
fun running. sum : 7
after: a=3, b=4, sum=fun running. sum : 7
run3
fun running. sum : 3

實現原理:Runtime 消息轉發三部曲

  1. 動態方法解析:+resolveInstanceMethod: 動態添加方法實現
  2. 快速轉發:-forwardingTargetForSelector: 指定備用接收者
  3. 正常轉發:-methodSignatureForSelector: + -forwardInvocation: 構建 NSInvocation 完整轉發

XYAOP 策略:

  • 攔截時,**將原方法重命名**(如 sumA:andB: → __original_sumA:andB:)
  • 在類中**動態添加同名方法**,實現指向 XYAOP 內部轉發入口
  • 轉發入口按順序執行:前置通知 → 原方法 (via NSInvocation) → 後置通知
  • 移除攔截時,恢復原方法名,刪除動態添加方法

關鍵 Runtime API

API作用
class_addMethod為類動態添加方法
class_replaceMethod替換方法實現 (IMP)
class_getInstanceMethod獲取 Method 結構體
method_setImplementation修改方法 IMP
class_getMethodImplementation獲取方法 IMP
method_getTypeEncoding獲取類型編碼 (用於 NSInvocation)

項目地址

完整代碼開源於 GitHub,歡迎 Star、PR:

https://github.com/uxyheaven/XYQuickDevelop (搜索 XYAOP.h)

適用場景與優勢

  • 無侵入式埋點:網絡請求耗時統計、參數合法性校驗
  • 調試神器:自動記錄所有公共方法調用鏈、參數、返回值
  • 熱修復預演:運行時動態替換方法實現
  • 比 Method Swizzling 更安全:不修改原方法 IMP,通過轉發機制隔離

掌握 Runtime 消息轉發,就掌握了 Objective-C 動態性的最高形態——**代碼即數據,結構即行為**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved