Skip to content

An aspect-oriented programming framework for Objective-C/Swift.

License

Notifications You must be signed in to change notification settings

WeZZard/ObjCGraft

Repository files navigation

Build Status Carthage Compatible

Introduction

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.

Usage

Grafting Implementations

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.

Removing Grafted Implementations

Objective-C

object_removeGraftedImplemenationOfProtocol(viewController, @protocol(MyViewControllerAspect), nil);

// or

object_removeAllGraftedImplemenations(viewController);

Swift

ObjCRemoveGraftedImplementation(of: MyViewControllerAspect.self, from: viewController)

// or

ObjCRemoveAllGraftedImplementations(from: viewController)

Known Issues

  • The process goes into an infinite loop when removing KVO observer unbalancedly from an object and that object is grafted with some implementations.

License

MIT

About

An aspect-oriented programming framework for Objective-C/Swift.

Resources

License

Stars

Watchers

Forks

Packages

No packages published