[转]NSProxy实现AOP方便为ios应用实现异常处理策略

[转载自:http://blog.csdn.net/yanghua_kobe/article/details/8395535html

 

  前段时间关注过objc实现的AOP,在GitHub找到了其中的两个库:AOP-in-Objective-C 和 AOP-for-Objective-C。第一个是基于NSProxy来实现的;第二个是基于GCD以及block实现的。二者都使用了Cocoa的运行时编程技术,将拦截器注入给代理对象,使其干涉真是对象的执行顺序从而达到给代码增长“切面”的目的,这里的模式就是一般的代理模式。git

  由于时间关系,暂时只看了第一个库的代码,下面简短地分析一下。github

  NSProxy:如其名,它出现的目的就是为了来“代理”一个真实对象的。这是Foundation库的内置实现。大部门人都知道NSObject是一般Cocoa中的根类,没错,但其实根类并不止一个,NSProxy也是跟NSObject的根类,只是它是个抽象类而且不是用于一般意义上的编程目的,因此不是那么广为人知(事实上我也是今天才知道)。而且NSObject看到它你觉得它是个类。但今天看NSProxy定义的时候,我发现它的头文件里是这样定义的:数据库

1 @interface NSProxy <NSObject>  


  开始我很莫名其妙,若是是继承自NSObject的话,应该是个冒号。这种写法明显就是实现协议的写法啊。因而,查看了一下资料,果真还有个NSObject的协议,而且NSObject类自身也实现了NSObject协议。具体资料请看这篇文章编程

  NSProxy与NSObject一虚一实,而且它们都实现了NSObject协议。这让NSProxy的实现类可以很好地“代理”NSObject子类,而且把NSObject协议抽象出来,也让他们可以共享某些行为。来看看它是如何工做的(测试代码见AOPLibTest.m文件):数组

  在你须要使用AOP的地方,你首先须要实例化一个对象,好比你须要实例化一个NSMutableArray,你须要使用AOPProxy来实例化它:app

1 NSMutableArray* testArray = (NSMutableArray*)[[AOPProxy alloc] initWithNewInstanceOfClass:[NSMutableArray class]]; 
 

  这里,实际上是间接实例化。它提供了一个接口,你把你的类名传给它,由它给你实例化。事实上,这是一种注入方式,而看完这个方法的定义你就会看到其实它返回给你的并非NSMutableArray的一个实例(实际上是AOPProxy,而它们之因此能互相强制转换是由于他们都实现了NSObject协议):iphone

 1 - (id) initWithNewInstanceOfClass:(Class) class {  
 2   
 3     // create a new instance of the specified class  
 4     id newInstance = [[class alloc] init];  
 5   
 6     // invoke my designated initializer  
 7     [self initWithInstance:newInstance];  
 8   
 9     // release the new instance  
10     [newInstance release];  
11   
12     // finally return the configured self  
13     return self;  
14 } 

  上面的self指代的就是AOPProxy,其中的initWithInstance方法:编辑器

1 - (id) initWithInstance:(id)anObject {  
2       
3     parentObject = [anObject retain];  
4   
5     methodStartInterceptors = [[NSMutableArray alloc] init];  
6     methodEndInterceptors = [[NSMutableArray alloc] init];  
7   
8     return self;  
9 }   

  能够看到,它在内部hold住了真实对象,而且实例化了两个数组,用来存储方法执行先后的拦截器集合。测试

   下面,咱们能够为NSMutableArray增长拦截器了:

1 [(AOPProxy*)testArray interceptMethodStartForSelector:@selector(addObject:)  
2                                     withInterceptorTarget:self  
3                                       interceptorSelector:@selector( addInterceptor: )];  
4       
5     [(AOPProxy*)testArray interceptMethodEndForSelector:@selector(removeObjectAtIndex:)  
6                                   withInterceptorTarget:self  
7                                     interceptorSelector:@selector( removeInterceptor: )];  

  由于这两个方法是AOPProxy的实例方法,因此在编写的时候仍是须要在强制转回来(其实你在XCode里跟踪的时候,这里的testArray一直都是APOProxy类型的对象,由于一开始他就是被AOPPorxy allo出来的)。这两个方法的实现很简单,只是将拦截器假如相应的数组中去,待后面取出来执行。

1 [testArray addObject:[NSNumber numberWithInt:1]];  
2 [testArray removeObjectAtIndex:0];  

  好了,看起来这里开始调用某个对象自己的行为了。为何说看起来呢?难道不是吗。固然不是,我在上面已经说过了,这里只是取名为testArray事实上它并非NSMutableArray的实例,而是AOPProxy的实例。但为何它仍是能够调用addObject这个方法呢,由于它被强制转换为NSMutableArray类型了,编辑器可以接受这样的类型转换,也就是这是合法的。因此编辑器认为它就是NSMutableArray类型的对象了,因此是能够这么调用的,但后面你会看到。在运行时其实编译器知道了它不是真实的NSMutableArray类型(也就是说它没法响应addObject以及removeObjectAtIndex这两个方法),因此把它交给了另外一个专门的方法来处理这些没法响应的消息:

  -(void)forwardInvocation:(NSInvocation*)anInvocation;

  这个方法实际上是继承自NSPorxy,NSProxy对它的实现其实就是抛出个异常,子类须要从新实现它,把它消息传递给真实的对象。详细信息参考官方文档

来看看它的实现:

 1 - (void)forwardInvocation:(NSInvocation *)anInvocation;  
 2 {  
 3     SEL aSelector = [anInvocation selector];  
 4   
 5     // check if the parent object responds to the selector ...  
 6     if ( [parentObject respondsToSelector:aSelector] ) {  
 7   
 8         [anInvocation setTarget:parentObject];  
 9   
10         //  
11         // Intercept the start of the method.  
12         //  
13           
14         NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
15   
16         for ( int i = 0; i < [methodStartInterceptors count]; i++ ) {  
17   
18             // first search for this selector ...  
19             AOPInterceptorInfo *oneInfo = [methodStartInterceptors objectAtIndex:i];  
20   
21             if ( [oneInfo interceptedSelector] == aSelector ) {  
22   
23                 // extract the interceptor info  
24                 id target = [oneInfo interceptorTarget];  
25                 SEL selector = [oneInfo interceptorSelector];  
26   
27                 // finally invoke the interceptor  
28                 [(NSObject *) target performSelector:selector withObject:anInvocation];  
29             }  
30         }  
31   
32         [pool release];  
33   
34         //  
35         // Invoke the original method ...  
36         //  
37           
38         [self invokeOriginalMethod:anInvocation];  
39   
40           
41         //  
42         // Intercept the ending of the method.  
43         //  
44           
45         NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];  
46           
47         for ( int i = 0; i < [methodEndInterceptors count]; i++ ) {  
48               
49             // first search for this selector ...  
50             AOPInterceptorInfo *oneInfo = [methodEndInterceptors objectAtIndex:i];  
51               
52             if ( [oneInfo interceptedSelector] == aSelector ) {  
53                   
54                 // extract the interceptor info  
55                 id target = [oneInfo interceptorTarget];  
56                 SEL selector = [oneInfo interceptorSelector];  
57                   
58                 // finally invoke the interceptor  
59                 [(NSObject *) target performSelector:selector withObject:anInvocation];  
60             }  
61         }  
62           
63         [pool2 release];          
64     }   
65 //    else {  
66 //        [super forwardInvocation:invocation];  
67 //    }  
68 }  

  能够看到这里让真实的对象调用了方法,而且干涉了对象的行为,在其先后加入了拦截器的执行操做。从而“优雅”地实现了AOP。

  该库中,还提供了两个Aspect:

    AOPMethodLoger-用于简单记录方法的日志;

    AOPThreadInvoker-用于在一个单独的线程上执行方法;

  以前在Java以及.net中已经很普遍地应用了AOP的实例了,常见的应用有作Log啊,异常捕获啊之类的。最近在作iOS的应用,其中也会牵扯到异常捕获的问题,特别是牵扯到数据库操做以及业务逻辑上的异常,老是写代码捕获块儿,费事还占面积。因此,我在里面又加了一个Aspect:AOPExcettionCatcher。很简单,就是在这里统一实现了异常捕获。

  从新实现了invokeOriginalMethod方法:

 1 - (void)invokeOriginalMethod:(NSInvocation *)anInvocation{  
 2     NSLog(@"%@",@"entry into try block");  
 3     @try {  
 4         [super invokeOriginalMethod:anInvocation];  
 5     }  
 6     @catch (NSException *exception) {  
 7         NSLog(@"%@",@"entry into catch block");  
 8         NSLog(@"%@",[exception reason]);  
 9     }  
10     @finally {  
11         NSLog(@"%@",@"entry into finally block");  
12     }  
13 }  

  固然了这只是应用之一,你还能够用它作更多的事情。

相关文章
相关标签/搜索