NSProxy實現AOP方便為ios應用實現異常處理策略

來源:互聯網
上載者:User

前段時間關注過objc實現的AOP。

在GitHub找到了其中的兩個庫:AOP-in-Objective-C 和 AOP-for-Objective-C

第一個是基於NSProxy來實現的;第二個是基於GCD以及block實現的;

兩者都使用了Cocoa的運行時編程技術,將攔截器注入給代理對象,使其幹涉真是對象的執行順序從而達到給代碼增加“切面”的目的,這裡的模式就是通常的代理模式。

因為時間關係,暫時只看了第一個庫的代碼,下面簡短地分析一下。

NSProxy:如其名,它出現的目的就是為了來“代理”一個真實對象的。這是Foundation庫的內建實現。大部門人都知道NSObject是通常Cocoa中的根類,沒錯,但其實根類並不止一個,NSProxy也是跟NSObject的根類,只是它是個抽象類別並且不是用於通常意義上的編程目的,所以不是那麼廣為人知(事實上我也是今天才知道)。並且NSObject看到它你以為它是個類。但今天看NSProxy定義的時候,我發現它的標頭檔裡是這樣定義的:

@interface NSProxy <NSObject>

開始我很莫名其妙,如果是繼承自NSObject的話,應該是個冒號。這種寫法明顯就是實現協議的寫法啊。於是,查看了一下資料,果然還有個NSObject的協議,並且NSObject類自身也實現了NSObject協議。具體資料請看這篇文章。

NSProxy與NSObject一虛一實,並且它們都實現了NSObject協議。這讓NSProxy的實作類別能夠很好地“代理”NSObject子類,並且把NSObject協議抽象出來,也讓他們能夠共用某些行為。

來看看它是如何工作的(測試代碼見AOPLibTest.m檔案):

在你需要使用AOP的地方,你首先需要執行個體化一個對象,比如你需要執行個體化一個NSMutableArray,你需要使用AOPProxy來執行個體化它:

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

這裡,其實是間接執行個體化。它提供了一個介面,你把你的類名傳給它,由它給你執行個體化。事實上,這是一種注入方式,而看完這個方法的定義你就會看到其實它返回給你的並不是NSMutableArray的一個執行個體(其實是AOPProxy,而它們之所以能互相強制轉換是因為他們都實現了NSObject協議):

- (id) initWithNewInstanceOfClass:(Class) class {    // create a new instance of the specified class    id newInstance = [[class alloc] init];    // invoke my designated initializer    [self initWithInstance:newInstance];    // release the new instance    [newInstance release];    // finally return the configured self    return self;}

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

- (id) initWithInstance:(id)anObject {        parentObject = [anObject retain];    methodStartInterceptors = [[NSMutableArray alloc] init];    methodEndInterceptors = [[NSMutableArray alloc] init];    return self;}

可以看到,它在內部hold住了真實對象,並且執行個體化了兩個數組,用來儲存方法執行前後的攔截器集合。

下面,我們可以為NSMutableArray增加攔截器了:

[(AOPProxy*)testArray interceptMethodStartForSelector:@selector(addObject:)                                    withInterceptorTarget:self                                      interceptorSelector:@selector( addInterceptor: )];        [(AOPProxy*)testArray interceptMethodEndForSelector:@selector(removeObjectAtIndex:)                                  withInterceptorTarget:self                                    interceptorSelector:@selector( removeInterceptor: )];

因為這兩個方法是AOPProxy的執行個體方法,所以在編寫的時候還是需要在強制轉回來(其實你在XCode裡跟蹤的時候,這裡的testArray一直都是APOProxy類型的對象,因為一開始他就是被AOPPorxy allo出來的)。這兩個方法的實現很簡單,只是將攔截器假如相應的數組中去,待後面取出來執行。

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

好了,看起來這裡開始調用某個對象本身的行為了。為什麼說看起來呢?難道不是嗎。當然不是,我在上面已經說過了,這裡只是取名為testArray事實上它並不是NSMutableArray的執行個體,而是AOPProxy的執行個體。但為什麼它還是可以調用addObject這個方法呢,因為它被強制轉換為NSMutableArray類型了,編輯器能夠接受這樣的類型轉換,也就是這是合法的。所以編輯器認為它就是NSMutableArray類型的對象了,所以是可以這麼調用的,但後面你會看到。在運行時其實編譯器知道了它不是真實的NSMutableArray類型(也就是說它無法響應addObject以及removeObjectAtIndex這兩個方法),所以把它交給了另一個專門的方法來處理這些無法響應的訊息:

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

這個方法其實是繼承自NSPorxy,NSProxy對它的實現其實就是拋出個異常,子類需要重新實現它,把它訊息傳遞給真實的對象。詳細資料參考官方文檔!

來看看它的實現:

- (void)forwardInvocation:(NSInvocation *)anInvocation;{    SEL aSelector = [anInvocation selector];    // check if the parent object responds to the selector ...    if ( [parentObject respondsToSelector:aSelector] ) {        [anInvocation setTarget:parentObject];        //        // Intercept the start of the method.        //                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];        for ( int i = 0; i < [methodStartInterceptors count]; i++ ) {            // first search for this selector ...            AOPInterceptorInfo *oneInfo = [methodStartInterceptors objectAtIndex:i];            if ( [oneInfo interceptedSelector] == aSelector ) {                // extract the interceptor info                id target = [oneInfo interceptorTarget];                SEL selector = [oneInfo interceptorSelector];                // finally invoke the interceptor                [(NSObject *) target performSelector:selector withObject:anInvocation];            }        }        [pool release];        //        // Invoke the original method ...        //                [self invokeOriginalMethod:anInvocation];                //        // Intercept the ending of the method.        //                NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];                for ( int i = 0; i < [methodEndInterceptors count]; i++ ) {                        // first search for this selector ...            AOPInterceptorInfo *oneInfo = [methodEndInterceptors objectAtIndex:i];                        if ( [oneInfo interceptedSelector] == aSelector ) {                                // extract the interceptor info                id target = [oneInfo interceptorTarget];                SEL selector = [oneInfo interceptorSelector];                                // finally invoke the interceptor                [(NSObject *) target performSelector:selector withObject:anInvocation];            }        }                [pool2 release];            } //    else {//        [super forwardInvocation:invocation];//    }}

可以砍到這裡讓真實的對象調用了方法,並且幹涉了對象的行為,在其前後加入了攔截器的執行操作。從而“優雅”地實現了AOP。

該庫中,還提供了兩個Aspect:

AOPMethodLoger-用於簡單記錄方法的日誌;

AOPThreadInvoker-用於在一個單獨的線程上執行方法;

之前在Java以及.net中已經很廣泛地應用了AOP的執行個體了,常見的應用有做Log啊,異常捕獲啊之類的。最近在做iOS的應用,其中也會牽扯到異常捕獲的問題,特別是牽扯到資料庫操作以及商務邏輯上的異常,總是寫代碼捕獲塊兒,費事還佔面積。所以,我在裡面又加了一個Aspect:AOPExcettionCatcher。很簡單,就是在這裡統一實現了異常捕獲。

重新實現了invokeOriginalMethod方法:

- (void)invokeOriginalMethod:(NSInvocation *)anInvocation{    NSLog(@"%@",@"entry into try block");    @try {        [super invokeOriginalMethod:anInvocation];    }    @catch (NSException *exception) {        NSLog(@"%@",@"entry into catch block");        NSLog(@"%@",[exception reason]);    }    @finally {        NSLog(@"%@",@"entry into finally block");    }}

當然了這隻是應用之一,你還可以用它做更多的事情。


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.