Execute Objective-C code Dynamically.
You should use 'git clone --recursive'.
git clone --recursive https://github.com/SilverFruity/OCRunner.git
or
git clone https://github.com/SilverFruity/OCRunner.git
cd OCRunner
git submodule update --init --recursive
The unit tests of OCRunner.framework has move to OCRunnerDemo。
-
Execute Objective-C code Dynamically。
-
Unit test coverage is 86%。
-
Support link system Non-inline C function by using Global C function declaration syntax in script。
-
Support structure declaration syntax in script. You can freely use structures in scripts。
-
Support enum declaration syntax.
-
Support typedef.
-
Support call multiple arguments function and method.
-
Support pointer operators : '&' and '*'.
-
Support Protocol.
-
Optinal libffi.a or build-in customized arm64 abi (modified from libffi)
Default using libffi.a.
- Do not use libffi.a: you should remove the reference of 'libffi' folder from project.
- Use libffi.a: add the libffi folder to project.
-
Not support pre-compile, C array declaration syntax.
Recommend: start eating from the unit test.
NSString * source =
@"@protocol Protocol1 <NSObject>"
@"@property (nonatomic,copy)NSString *name;"
@"-(NSUInteger)getAge;"
@"-(void)setAge:(NSUInteger)age;"
@"@end"
@"@protocol Protocol2 <Protocol1>"
@"- (void)sleep;"
@"@end"
@"@interface TestObject : NSObject <Protocol2>"
@"@property (nonatomic,copy)NSString *name;"
@"@end"
@"@implementation TestObject"
@"- (NSUInteger)getAge{"
@" return 100;"
@"}"
@"-(void)setAge:(NSUInteger)age{"
@"}"
@"- (void)sleep{"
@"}"
@"@end";
[ORInterpreter excute:source];
Class testClass = NSClassFromString(@"TestObject");
NSAssert([testClass conformsToProtocol:NSProtocolFromString(@"Protocol1")]);
NSAssert([testClass conformsToProtocol:NSProtocolFromString(@"Protocol2")]);
id object = [[testClass alloc] init];
NSAssert([object conformsToProtocol:NSProtocolFromString(@"Protocol1")]);
NSAssert([object conformsToProtocol:NSProtocolFromString(@"Protocol2")]);
pod 'OCRunner' #for all architectures, include libffi.a
pod 'OCRunnerArm64' #only for arm64 or amr64e, no libffi.a
Such as #define, #if etc.
- Problem 1:if Class1 have five method (a,b,c,d,e) and several properties, if i only want to hot fix 'a' method, how can i do it ? anwser: you only need to imp the 'a' method in scripts.
The shortest way:
@implementation ORTestReplaceClass
- (int)otherMethod{
return 10;
}
- (int)test{
return [self otherMethod];
}
@end
If want to add properties (not support add ivars), you should:
@interface ORTestReplaceClass : NSObject
@property (assign, nonatomic) NSInteger num;
@end
@implementation ORTestReplaceClass
- (int)otherMethod{
return 10;
}
- (int)test{
return [self otherMethod];
}
@end
In this situation, ORTestReplaceClass inherit NSObjece.
@implementation ORTestReplaceClass
- (int)otherMethod{
return 10;
}
- (int)test{
return [self otherMethod];
}
@end
if you want to add ivar, property or customized superClass,you should imp @interface.
Notice: ivar must be used in new Class.
@interface ORTestReplaceClass : NSObject
{
int _testValue;
id _testObject;
}
@property (assign, nonatomic) NSInteger num;
@end
@implementation ORTestReplaceClass
{
int _impivar;
}
- (int)otherMethod{
return 10;
}
- (int)test{
return [self otherMethod];
}
@end
@implementation Demo
- (instancetype)initWithBaseUrl:(NSURL *)baseUrl{ }
- (NSString *)method2:(void(^)(NSString *name))callback{ }
@end
@implementation Demo (Category)
- (NSString *)method3:(void(^)(NSString *name))callback{ }
@end
Not surpport NS_ENUM和NS_OPTION.
You should use C syntax.
//typedef NS_OPTIONS(NSUInteger, UIControlEvents) {}
//convert to this
typedef enum: NSUInteger {
}UIControlEvents;
The referenced structure must be declared in advance.
// CGPoint must be in front of CGRect
struct CGPoint {
CGFloat x;
CGFloat y;
};
// CGSize must be in front of CGRect
struct CGSize {
CGFloat width;
CGFloat height;
};
struct CGSize {
CGPoint point;
CGSize size;
};
Way 1:
// Need write those code in Application files
// Struct
ORStructDeclareTable *table = [ORStructDeclareTable shareInstance];
[table addStructDeclare:[ORStructDeclare structDecalre:@encode(CGPoint) keys:@[@"x",@"y"]]];
// Constant
[MFScopeChain.topScope setValue:[MFValue valueWithLongLong:DISPATCH_QUEUE_PRIORITY_HIGH] withIndentifier:@"DISPATCH_QUEUE_PRIORITY_HIGH"];
// Enum is similar to Constant
[MFScopeChain.topScope setValue:[MFValue valueWithULongLong:UIControlEventTouchDragInside] withIndentifier:@"UIControlEventTouchDragInside"];
Way 2:
// Need write those code in Scripts
typedef struct CGPoint {
CGFloat x;
CGFloat y;
} CGPointss;
typedef enum: NSUInteger{
UIControlEventTouchDown = 1 << 0,
UIControlEventTouchDownRepeat = 1 << 1,
UIControlEventTouchDragInside = 1 << 2,
UIControlEventAllTouchEvents = 0x00000FFF,
}UIControlEvents;
// it will add four types: CGPoint, CGPointss, UIControlEvents
// add four constants: UIControlEventTouchDown UIControlEventTouchDownRepeat UIControlEventTouchDragInside UIControlEventAllTouchEvents
// use it in Scripts
typedef NSInteger dispatch_once_t;
// problem code:
typedef long long IntegerType;
typedef IntegerType dispatch_once_t;
- Pre-compile function:
[MFScopeChain.topScope setValue:[MFValue valueWithBlock:^void(dispatch_queue_t queue, void (^block)(void)) {
dispatch_async(queue, ^{
block();
});
}] withIndentifier:@"dispatch_async"]
- Non-inline function:
// add this in Scripts
void NSLog(NSString *format, ...);
-
Inline function
For example: dispatch_get_main_queue
- Way 1
// the code in Application files [MFScopeChain.topScope setValue:[MFValue valueWithBlock:^id() { return dispatch_get_main_queue(); }]withIndentifier:@"dispatch_get_main_queue"];
- Way 2
// write in script. OCRunner will auto print it in console on the debug mode. dispatch_queue_main_t dispatch_get_main_queue(void); // the code in Application files [ORSystemFunctionTable reg:@"dispatch_get_main_queue" pointer:&dispatch_get_main_queue];
-
(CGRectMake etc.) Inline function、Custom function
// write in script
CGRect CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
CGRect rect;
rect.origin.x = x; rect.origin.y = y;
rect.size.width = width; rect.size.height = height;
return rect;
}
#import can be omitted.
- int a[x]
- typeof
- @optional
- @encode
- @synchronized
- @try
- @catch
- @available
- @protocol
- @autoreleasepool
- @dynamic
- @synthesize
- IBOutlet
- IBAction
- IBInspectable