A Tutorial for using AspectCocoa.
The framework as availble from http://www.ccs.neu.edu/home/igotimac/AspectCocoa.zip is compiled as an embedable framework. This tutorial assumes you are using XCode on Tiger, but there’s no particular reason why it won’t work on older setups. (If you’re trying to get it working on an older setup, you can ask me for help JacobBurkhart).
So to get started, download the AspectCocoa framework, and open a version of Apple’s example program Sketch.
Part one, compiling Sketch with the AspectCocoa framework:
At this point, you should be able to compile and run Sketch.
Part two, Generating AspectCocoa method stubs: Edit Sketch_main.m, and add the following Code: To start with, it should look something like this:
int main(int argc, const char *argv[]) { return NSApplicationMain(argc, argv); }
This main function is the most convenient place to start messing around with Aspects, because it allows us to configure and load then before anything else happens. Unfortunately, since we’ll be putting code in before NSApplicationMain is called, we’ll need to setup our out autorelease pools. (ohh and we’ll also need to import Aspect Cocoa) so…
#import <AspectCocoa/AspectCocoa.h> int main(int argc, const char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; //this is the best place for doing all your AOP [pool release]; return NSApplicationMain(argc, argv); }
Next, let’s make a point cut.
ACPointCut * pointCut = [[ACPointCut alloc] initDefault];
This “Default point cut picks out all methods on all classes that are not park of AppKit or Foundation. So, in this case, it picks out all methods on all classes defined in Sketch.app. Alternately, we could pick out everything with:
ACPointCut * pointCut = [[ACPointCut alloc] init];
Now, we neeed to generate those method stubs we were talking about. our main should now look something like this. (you should change @”/Users/igotimac/Sketch/generatedAdds/SketchAOPAdditions” to point to some convenient folder insider you Sketch project)
#import <AspectCocoa/AspectCocoa.h> int main(int argc, const char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
ACPointCut * pointCut = [[ACPointCut alloc] initDefault];
[ACCodeGenerator generateCodeForPointCut: pointCut
writeTo: @"/Users/igotimac/Sketch/generatedAdds/SketchAOPAdditions"];
[pool release];
return NSApplicationMain(argc, argv); }
We will run Sketch, once. and we should see something like this logged out:
2005-07-22 10:37:55.848 Sketch[1010] writting in pieces 2005-07-22 10:37:55.849 Sketch[1010] count 90 2005-07-22 10:37:55.849 Sketch[1010] 0 from 0 length 90 2005-07-22 10:37:55.849 Sketch[1010] writting 2005-07-22 10:37:55.849 Sketch[1010] category is SketchAOPAdditions0
Which means that 2 new files have been created, and should now be included i your project: SketchAOPAdditions0.h and SketchAOPAdditions0.m import then as you see fit.
If you’re concerned about some error messages like:
2005-07-22 10:37:55.847 Sketch[1010] couldn’t find code/string for type CGRect
Don’t be. This means that AspectCocoa could not create a method stub for some method that takes a CGRect struct as an argument (or return type). While we currently support some typical foundation structs like NSRect. We do not support user defined structs at the momment. All this means, is that you won’t be able to advise a method that takes a struct as an argument unless that struct is one of the common foundation structs.
So anyway… we should remove that generate code statement since we won’t be needing it now that we have the code we want. And, now we’ll actually create and load an aspect. so out final main should look like:
#import <AspectCocoa/AspectCocoa.h>
int main(int argc, const char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
ACPointCut * pointCut = [[ACPointCut alloc] initDefault]; //[ACCodeGenerator generateCodeForPointCut: pointCut //writeTo: @"/Users/igotimac/Sketch/generatedAdds/SketchAOPAdditions"];
ACAspect * myAspect = [[ACAspect alloc] initWithPointCut: pointCut andAdviceObject: [ACLoggingAdvice new]]; [myAspect load];
[pool release];
return NSApplicationMain(argc, argv); }
Now when we compile and run Sketch, we should see debug logs galore, like this:
2005-07-22 10:45:52.356 Sketch[1232] -before graphicWithPropertyListRepresentation: on SKTGraphic 2005-07-22 10:45:52.356 Sketch[1232] –before init on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —before undoManager on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —-before document on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —-after document on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —after undoManager on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —before undoManager on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —-before document on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —-after document on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —after undoManager on SKTRectangle 2005-07-22 10:45:52.357 Sketch[1232] —before undoManager on SKTRectangle 2005-07-22 10:45:52.358 Sketch[1232] —-before document on SKTRectangle 2005-07-22 10:45:52.358 Sketch[1232] —-after document on SKTRectangle 2005-07-22 10:45:52.358 Sketch[1232] —after undoManager on SKTRectangle 2005-07-22 10:45:52.358 Sketch[1232] —before undoManager on SKTRectangle
Not that that’s particularly usefull to you… and you’re probably annoyed by the repeated:
2005-07-22 10:44:57.885 Sketch[1232] couldn’t find code/string for type CGSize
messages
So the tutorial shall continue another day. And maybe do something usefull. In the meantime, you can look at the rest of AspectCocoaDocumentation and see if you can make it do something you find interesting