objective-c 面向切面编程(AOP)

时间:2015-03-31 00:57:03

浅谈objective-c 面向切面变成(注释:学习他人代码)

原文请参考:技术哥 && csdn博客 ## 方案一(个人觉得合适的方式) 通过使用类别(category)对运行是的方法,进行替换,实现面向切面编程的思想。 1、创建一个类别的文件 2、替换运行时方法的方法 3、编写要替换的方法 4、执行方法

具体方式~

2、替换运行时方法的方法(注:要引入运行时库文件#import <objc/objc-runtime.h>)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        // 运行时,交换执行的方法
        void swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector)
        {
            // 原始方法
            Method originalMethod = class_getInstanceMethod(class, originalSelector);
            // 替换方法
            Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

            // 对一个类新增一个方法,返回新增方法是否成功, 目的是为后面替换方法。
            BOOL didAddMethod = class_addMethod(class, swizzledSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));

            if (didAddMethod) {
                // 如果添加成功,则替换实现方法体
                class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
            } else {
                // 添加失败,还原替换
                method_exchangeImplementations(originalMethod, swizzledMethod);
            }
        }
    

3、编写要替换的方法

1
2
3
4
5
6
7
8
9
10
// 替换的方法,一般用于log日志等功能
- (void)swizzled_viewDidAppear:(BOOL)animated
{
    // 运行时的代码,不会是递归方式调用的~
    [self swizzled_viewDidAppear:animated];

    if (![self isKindOfClass:[UINavigationController class]]) {
    NSLog(@"%@~~~~%@", NSStringFromClass([self class]), self.title);
    }
}

4、执行方法

1
2
3
4
+ (void)load
{
    swizzleMethod([self class], @selector(viewDidLoad), @selector(swizzled_viewDidAppear:));
}

最后,在需要的地方,引入类别的头文件即可实现,一次导入,多出执行,真正的实现面向切面变成,至于为什么,只需要引入头文件就可以实现函数的替换,还在探索中~

方案二(这种也有硬编码的嫌疑~)

主要是通过代理协议实现的~,实现原理还在琢磨中~,代码先记录学习~

  1. 创建一个协议
1
2
3
4
5
6
7
8
9
#import <Foundation/Foundation.h>

@protocol DPDynamicProtocol <NSObject>

@required
- (void)doSomthing;
- (void)doOtherthing;

@end

2.创建实现协议的NSProxy类,在此类中拦截,捕捉异常、日志等事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#import <Foundation/Foundation.h>
#import "DPDynamicProtocol.h"

@interface DPDynamicProxy : NSProxy <DPDynamicProtocol>
{
    @private
    id<DPDynamicProtocol> _obj; // 协议的对象
}

- (id)initWithObject:(id<DPDynamicProtocol>)obj;

@end

#import "DPDynamicProxy.h"

@implementation DPDynamicProxy

- (id)initWithObject:(id<DPDynamicProtocol>)obj
{
    _obj = obj;

    return self;
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    if (_obj) {
        NSLog(@"proxy invocation obj method: %s", __func__);

        [invocation setTarget:_obj];
        [invocation invoke];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    if ([_obj isKindOfClass:[NSObject class]]) {
        return [(NSObject *)_obj methodSignatureForSelector:sel];
    }

    return [super methodSignatureForSelector:sel];
}

- (void)doSomthing
{
    NSLog(@"proxy do something");

    [_obj doSomthing];
}

- (void)doOtherthing
{
    NSLog(@"proxy do doOtherthing");

    [_obj doOtherthing];
}
@end
  1. 对应需要功能的类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#import <Foundation/Foundation.h>
#import "DPDynamicProtocol.h"

@interface DPNormalObject : NSObject <DPDynamicProtocol>

@end

#import "DPNormalObject.h"

@implementation DPNormalObject

- (void)doOtherthing
{
//    NSLog(@"normal object do otherthing");
}

- (void)doSomthing
{
//    NSLog(@"normal object do something");
}

@end
Loading Disqus comments...
Table of Contents