An aspect-oriented programming framework in Objective-C/Swift. Implemented with is-a swizzling and is KVO compliant.
You can use this framework to inject your custom implementation to any method of any Objective-C object without affecting other instances of the same type.
To know the story about how I compose this framework, check A Story of Implementing Aspect-Oriented Programming in Objective-C and Swift.
You need three things to inject(graft) your custom implementation to a method of an object.
- An Objective-C based protocol which defines the "aspect".
- An Objective-C based class which offers custom implementations of the aspect.
- An Objective-C object to inject(graft) with the custom implementations of the aspect.
For example, if you want to add some behavior, such as printing "Foo"
to viewDidLoad
in an instance of type of UIViewController
without
affecting other instances of the same type, you can do as below:
First, you need to define the "aspect" to be "manipulated" with.
MyViewControllerAspect.h
@protocol MyViewControllerAspect<NSObject>
- (void)viewDidLoad;
@end
Then, you need to implement this "aspect" on a class. This is recommended to be done in Objective-C, because you don't have to take those complex compile-time resolving in Swift into consideration when coding with Objective-C.
MyViewController.h
#import <UIKit/UIKit.h>
@interface MyViewController: UIViewController<MyViewControllerAspect>
@end
MyViewController.m
#import "MyViewController.h"
@implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"Foo");
}
@end
Last, you need to graft the implementation defined by the "aspect" from the previously defined class to the object.
Objective-C
UIViewController * viewController = [UIViewController alloc] init];
object_graftImplemenationOfProtocolFromClass(viewController, @protocol(MyViewControllerAspect), [MyViewController class]);
Swift
let viewController = UIViewController()
ObjCGraftImplementation(of: MyViewControllerAspect.self, from: MyViewController.self, to: viewController)
Now, your viewController
object can log "Foo" when the viewDidLoad
was
called.
Objective-C
object_removeGraftedImplemenationOfProtocol(viewController, @protocol(MyViewControllerAspect), nil);
// or
object_removeAllGraftedImplemenations(viewController);
Swift
ObjCRemoveGraftedImplementation(of: MyViewControllerAspect.self, from: viewController)
// or
ObjCRemoveAllGraftedImplementations(from: viewController)
- The process goes into an infinite loop when removing KVO observer unbalancedly from an object and that object is grafted with some implementations.
MIT