AOP(面向切面編程)將日誌、性能統計、權限檢查等**橫切關注點**從業務邏輯中剝離。Objective-C 強大的 Runtime 機制(動態方法解析、消息轉發)使 AOP 實現極其優雅。本文展示一個生產級攔截器 XYAOP 的核心原理與使用姿勢。
-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
+resolveInstanceMethod: 動態添加方法實現-forwardingTargetForSelector: 指定備用接收者-methodSignatureForSelector: + -forwardInvocation: 構建 NSInvocation 完整轉發XYAOP 策略:
sumA:andB: → __original_sumA:andB:)XYAOP 內部轉發入口| 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)
掌握 Runtime 消息轉發,就掌握了 Objective-C 動態性的最高形態——**代碼即數據,結構即行為**。