Skip to content
An aspect-oriented programming framework for Objective-C/Swift.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
ObjCGraft.xcodeproj
ObjCGraft
ObjCGraftTests
.gitignore
.travis.yml
LICENSE
README.md
使用說明.md

README.md

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

You can’t perform that action at this time.