OCFuntime 0.3.1-beta1

OCFuntime 0.3.1-beta1

TestsTested
LangLanguage Obj-CObjective C
License MIT
ReleasedLast Release Jun 2016

Maintained by Alexey Belkevich.



OCFuntime 0.3.1-beta1

About

OCFuntime is a toolkit for Objective-C runtime.

Features

  • Change instance or class method implementation and revert it back
  • Inject property of any type to any class
  • Modular structure: each task extracted as Cocoapods subspec

Change method implementation

Method implementation changing allows to run block of code on corresponding method call. Don't be confused with method swizzling.

Instance method implementation block should conform signature:

method_return_type ^(id selfInstance, arg1_type arg1, arg2_type arg2, ...)

Class method implementation block should conform signature:

method_return_type ^(Class theClass, arg1_type arg1, arg2_type arg2, ...)

Installation

Add pod 'OCFuntime/Methods' to Podfile

Example

@interface MyClass : NSObject
- (void)someInstanceMethod:(NSObject *)someArg;
+ (NSInteger)someClassMethod;
@end
#import "OCFuntime+Methods.h"
...
OCFuntime *funtime = [[OCFuntime alloc] init];
// Change instance method implementation
[funtime changeClass:MyClass.class instanceMethod:@selector(someInstanceMethod:)
      implementation:^(MyClass *instance, NSObject *someArg)
{
   NSLog(@"Changed instance method with arg %@!", someArg);
}];
// Change class method implementation
[funtime changeClass:MyClass.class classMethod:@selector(someClassMethod)
      implementation:^(Class theClass)
{
    NSLog(@"Changed class method of %@!", NSStringFromClass(theClass));
    return 5;
}];
//Revert method to default implementation
[funtime revertClass:MyClass.class instanceMethod:@selector(someInstanceMethod)];
[funtime revertClass:MyClass.class classMethod:@selector(someClassMethod)];
// Revert all methods of class to default implementation
[funtime revertClassMethods:MyClass.class];
// Revert all changed methods to default implementation
[funtime revertAllMethods];

Notes

  • Skip arguments in implementation block signature if you don't need them.
  • Skipping value return will cause undefined behaviour.
  • After OCFuntime instance will be deallocated all changed methods will be reverted to default implementations. To avoid it use Shared Instance of OCFuntime.
  • Changing unexisted method will rise an exception.
  • Changing implementation isn't thread safe.

NSObject Category

Run method implementation changing on corresponding class with NSObject category.

Add pod 'OCFuntime/NSObject+OCFMethods' to Podfile

#import "NSObject+OCFMethods.h"
...
// Change class method implementation
[MyClass changeClassMethod:@selector(someClassMethod) implementation:^
{
    NSLog(@"Changed 'someClassMethod'");
    return 0;
}];
// Change instance method implementation
[MyClass changeInstanceMethod:@selector(someInstanceMethod)
               implementation:^(MyClass *instance, NSObject *someArg)
{
    NSLog(@"Called changed method of %@ with arg %@", instance, someArg);
}];
// Revert class method implementation
[MyClass revertClassMethod:@selector(someStaticMethod)];
// Revert instance method implementation
[MyClass revertInstanceMethod:@selector(someMethod)];
// Revert all methods
[MyClass revertMethods];

NSObject+OCFMethods subspec includes Methods and Shared subspecs as dependencies. Don't include them to Podfile.

Inject property

Property injection allow to use @dynamic properties as it've been @synthesize. And it's the best way to avoid "no synthesized properties in objective-c categories" restriction. Injection is based on Message Forwarding and Associated Objects.

Installation

Add pod 'OCFuntime/Properties' to Podfile

Example

@interface SomeClass : NSObject
@property (nonatomic, strong) id objectStrongProperty;
@property (nonatomic, assign) NSInteger integerProperty;
@end
...
@implementation
@dynamic objectStrongProperty, integerProperty;
@end
...
#import "OCFuntime+Properties.h"
#import "SomeClass.h"
...
// Inject properties
OCFuntime *funtime = [[OCFuntime alloc] init];
[funtime injectClass:SomeClass.class property:@"objectStrongProperty"];
[funtime injectClass:SomeClass.class property:@"integerProperty"];
// Use properties
SomeClass *someInstance = [[SomeClass alloc] init];
someInstance.objectStrongProperty = [[NSObject alloc] init];
someInstance.integerProperty = 5;
// Remove injected property
[funtime removeClass:SomeClass.class property:@"objectStrongProperty"];
// Remove all class injected properties
[funtime removeClassProperties:SomeClass.class];
// Remove all injected properties
[funtime removeAllProperties];

Notes

  • atomic properties injected as nonatomic. It's will be fixed in one of the next releases.
  • After OCFuntime instance will be deallocated all injected properties will be removed. To avoid it use Shared Instance of OCFuntime.
  • If property doesn't defined in class interface exception will raise.
  • If property synthesized or already injected exception will raise.
  • Property injection doesn't break methods forwardInvocation: and methodSignatureForSelector: because of Swizzling.
  • Property injection isn't thread safe.

NSObject Category

Run property injection on corresponding class with NSObject category.

Add pod 'OCFuntime/NSObject+OCFProperties' to Podfile

#import "NSObject+OCFProperties.h"
...
// Inject properties
[SomeClass injectProperty:@"objectStrongProperty"];
[SomeClass injectProperty:@"integerProperty"];
// Remove property
[SomeClass removeProperty:@"objectStrongProperty"];
// Remove all injected properties of class
[SomeClass removeProperties];

NSObject+OCFProperties subspec includes Properties and Shared subspecs as dependencies. Don't include them to Podfile.

Other

Shared instance

Add pod 'OCFuntime/Shared' to Podfile

#import "OCFuntime+Shared.h"
...
[OCFuntime.shared changeClass:MyClass.class
               instanceMethod:@selector(someMethod)]
               implementation:^
{
    NSLog(@"Changed someMethod with shared instance")
}];

Default subspec

Default subspec pod 'OCFuntime' includes all subspecs. Use @import "OCFuntimeHeader.h" to enable all features of OCFuntime.

History

Releases

Updates

Follow updates @okolodev