AspectObjectiveC Manual

Table of Contents

  1. Introduction
  2. Requirements
  3. Downloading and Installation
  4. API Documentation
  5. Usage
  6. Project Status
  7. Known Problems
  8. Contributing and Contact

Introduction

AspectObjectiveC (AOC) brings aspect oriented programming functionality to Objective-C. Basically, it allows you to execute arbitrary code before, instead of, or after any method on any class at runtime. You can replace entire methods, alter return values of methods, or alter the arguments to methods for which you don't have the code (e.g., in third party frameworks). Note that using AspectObjectiveC to replace methods within itself may rip a hole in the fabric of spacetime.

It is available under the MIT license (see LICENSE.txt).

The project is hosted on github: http://github.com/tomdalling/AspectObjectiveC

Requirements

AOC works on OSX 10.5 and 10.6, for architectures i386 and x86_64.

It probably works on 10.4 and different architectures like ppc, but has not been tested. If you would like to compile it for 10.4 or another architecture, feel free to contact me via the AspectObjectiveC github page.

AOC is not available on iOS (formerly "iPhone OS") because it relies on the libffi closure API, which is not available on iOS.

Downloading and Installation

You can build the project yourself, or just download the latest compiled version from the project's github download page: http://github.com/tomdalling/AspectObjectiveC/downloads.

The framework can be added to an Xcode project using the following steps.

1. Add the framework folder to the project. Drag and drop the AspectObjectiveC.framework folder into the project.
2. Link against the framework. Under the project's target, drag AspectObjectiveC.framework from the place it was dropped in the first step, and drop it into the build phase named Link Binary With Libraries
3. Copy the framework into the application bundle as a private framework. Under the project's target, create a New Copy Files Build Phase. In the info window for the new build phase, set Destination to Frameworks. Drag AspectObjectiveC.framework from the place it was dropped in the first step, and drop it under the newly created build phase.
4. Include the headers. In files that use the framework, include the framework headers like so:

#import <AspectObjectiveC/AOC.h>

API Documentation

The API documentation is available here: AspectObjectiveC API Documentation

A docset for Xcode integration is also available in the doc folder.

Usage

1. Create an Advice Object

Advice objects contain the code that runs before/after/instead of a method. Advice objects must implement the AOCAdviceProtocol protocol. The class AOCAdvice is a base class that is provided for convenience, and implements AOCAdviceProtocol.

Check the API documentation for AOCAdviceProtocol and AOCAdvice.

The following is an example advice class. All three methods are optional.

@interface SomeAdvice : AOCAdvice
-(double) adviceBeforeCelciusToFahrenheit:(double)celcius;
-(double) adviceInsteadOfCelciusToFahrenheit:(double)celcius;
-(double) adviceAfterCelciusToFahrenheit:(double)celcius;
@end

@implementation SomeAdvice

-(double) adviceBeforeCelciusToFahrenheit:(double)celcius;
{
    // Advice before can be used to alter method arguments before they
    // reach the method. In this case, we're going to set the `celcius` arg
    // to `10.0`, ignoring whatever the arg actually was.
    
    double newCelcius = 10.0;
    NSLog(@"BEFORE: celcius was %f, but I'm changing it to %f", celcius, newCelcius);
    [[self invocation] setArgument:&newCelcius atIndex:2];
    
    return 0.0; //return value is ignored
}

-(double) adviceInsteadOfCelciusToFahrenheit:(double)celcius;
{
    // "Instead of" advice completely replaces a method.
    // In this case, it will just halve whatever celcius is.
    double halfCelcius = celcius / 2.0;
    NSLog(@"INSTEAD OF: celcius is %f. will return %f", celcius, halfCelcius);
    return halfCelcius; //return value is NOT ignored
}

-(double) adviceAfterCelciusToFahrenheit:(double)celcius;
{
    // Advice after can be used to change the return value of a method.
    // In this case, it will triple whatever the return value was
    
    double returnValue;
    [[self invocation] getReturnValue:&returnValue];
    double newReturnValue = 3.0 * returnValue;
    [[self invocation] setReturnValue:&newReturnValue];
    
    NSLog(@"AFTER: return value was %f, but I tripled it to %f", returnValue, newReturnValue);
    return 0.0; //return value is ignored
}

@end

2. Install the advice object

Next, the advice object has to be installed on a method of a class. Once installed, the advice will run whenever the method is called on any instance of the class.

Check the API documentation for AOCAspectManager.

Advice is installed like so:

[[AOCAspectManager defaultAspectManager] installAdvice:[[SomeAdvice new] autorelease]
                                           forSelector:@selector(celciusToFahrenheit:)
                                               ofClass:[SomeOtherClass class]
                                                 error:NULL];

3. Running the Advice

Running the following code...

SomeOtherClass* soc = [[SomeOtherClass new] autorelease];
double returnValue = [soc celciusToFahrenheit:50.0];
NSLog(@"Final return value is %f", returnValue);

Should produce the following console output...

BEFORE: celcius was 50.000000, but I'm changing it to 10.000000
INSTEAD OF: celcius is 10.000000. will return 5.000000
AFTER: return value was 5.000000, but I tripled it to 15.000000
Final return value is 15.000000

Project Status

This is the 1.0 release of AOC, and should be considered stable. I will continue active development if there is sufficient interest in the project, otherwise I will only be fixing bugs and accepting patches from other people.

Known Problems

Contributing and Contact

I'm open to bug fixes, new features, and optimisations. One feature I would like to add is some form of pointcut syntax so that advice can be added to multiple methods at once, instead of one at a time. If you wish to contribute, please do so via the AspectObjectiveC github project page.

So far, I (Tom Dalling) am the only contributor to the project. You can contact me via github.