Aspect Oriented Programming in Objective-C

Aspect Oriented Programming is nice. It allows you to add functionality to objects that are not related to the program’s main logic – for this reason there are also called secondary or supporting functionality. You can read various publications on this a good starting point being Wikipedia’s article on AOP: http://en.wikipedia.org/wiki/Aspect-oriented_programming .

Let’s consider the following scenario: we have an instance of NSMutableArray and we would like to be notified for the following events: whenever its addObject: method is invoked and whenever it finished executing. We easily might need this functionality for the reason that we would like to validate the parameter addObject: receives against our business rules, and after the method finished executing we would like to send an NSNotification to other parts of the system letting them know that our array has changed.

The solution in Objective-C comes from its dynamic behavior, and it’s very flexible message sending mechanism, than can be used to create dynamic proxies that act like the original object but also add functionality to them.

So let’s start by creating an AOPProxy class that inherits from NSProxy and makes sure it behaves exactly like the object it proxies.

@interface AOPProxy : NSProxy {

@protected
    id parentObject;
}

The parentObject is a reference to the original object for which we are going to act like a proxy and we are going to set this in the AOPProxy initializer.

The implementation of this AOPProxy has to override the following methods: -isKindOfClass: , -conformsToProtocol: , -respondsToSelector: , -methodSignatureForSelector: to be able to provide meta information to callers about itself. I’m going to show the implementation only in case of -isKindOfClass: since the implementation of the rest of the methods would look generally the same:

- (BOOL)isKindOfClass:(Class)aClass;
{
    return [parentObject isKindOfClass:aClass];
}

After we made sure that our proxy will respond to the above methods, we need to make sure that our proxy will forward the method invocations to the original instance, and this happens in the -forwardInvocation: method:

- (void)forwardInvocation:(NSInvocation *)anInvocation;
{
    SEL aSelector = [anInvocation selector];

    // check if the parent object responds to the selector ...
    if ( [parentObject respondsToSelector:aSelector] ) {

        [anInvocation setTarget:parentObject];

        // this is the point where we can jump in and execute our code ...
        [anInvocation invoke];
    }
}

Finally, extending this idea we can come up with methods that add a target and selector to be invoked before and after the [anInvocation invoke]; happens – which will give exactly the desired functionality of our proxy class.

Using the AOPProxy class we can do something like this:

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

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

[(AOPProxy*)testArray interceptMethodEndForSelector:@selector(addObject:)
                             withInterceptorTarget:self
                             interceptorSelector:@selector(addObjectEndInterceptor:)];

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

[testArray release];

If you would like to check the code out you can download it from:https://github.com/moszi/AOP-in-Objective-C .