Skip to content

Adding new extensions

bang edited this page Jul 4, 2015 · 3 revisions

##API

All extensions should extend JPExtension:

@protocol JPExtensionProtocol <NSObject>
@optional
- (void)main:(JSContext *)context;

- (size_t)sizeOfStructWithTypeEncoding:(NSString *)typeEncoding;
- (NSDictionary *)dictOfStruct:(void *)structData typeEncoding:(NSString *)typeEncoding;
- (void)structData:(void *)structData ofDict:(NSDictionary *)dict typeEncoding:(NSString *)typeEncoding;
@end

@interface JPExtension : NSObject <JPExtensionProtocol>
+ (instancetype)instance;
- (void *)formatPointerJSToOC:(JSValue *)val;
- (id)formatPointerOCToJS:(void *)pointer;
- (id)formatJSToOC:(JSValue *)val;
- (id)formatOCToJS:(id)obj;
@end

##Add support for struct

Struct is represented as hash object in JS, which is NSDictionary in OC. So we should convert struct to NSDictionary when passing from OC to JS, and covert NSDictionary to struct when passing from JS to OC.

Implement the 3 methods related with struct in JPExtensionProtocol to add support for the custom struct type, for example:

@interface JPCGTransform : JPExtension
@end

@implementation JPCGTransform
- (size_t)sizeOfStructWithTypeEncoding:(NSString *)typeEncoding
{
    if ([typeEncoding rangeOfString:@"CGAffineTransform"].location == 1) {
        return sizeof(CGAffineTransform);
    }
    return 0;
}

- (NSDictionary *)dictOfStruct:(void *)structData typeEncoding:(NSString *)typeEncoding
{
    if ([typeEncoding rangeOfString:@"CGAffineTransform"].location == 1) {
        CGAffineTransform *trans = (CGAffineTransform *)structData;
        return @{@"tx": @(trans->tx), @"ty": @(trans->ty), @"a": @(trans->a), @"b": @(trans->b), @"c": @(trans->c), @"d": @(trans->d)};
    }
    return nil;
}

- (void)structData:(void *)structData ofDict:(NSDictionary *)dict typeEncoding:(NSString *)typeEncoding
{
    if ([typeEncoding rangeOfString:@"CGAffineTransform"].location == 1) {
        trans->tx = [dict[@"tx"] floatValue];
        trans->ty = [dict[@"ty"] floatValue];
        trans->a = [dict[@"a"] floatValue];
        trans->b = [dict[@"b"] floatValue];
        trans->c = [dict[@"c"] floatValue];
        trans->d = [dict[@"d"] floatValue];
    }
}
@end

Struct type CGAffineTransform is avaliable in JS now:

require('JPEngine').addExtensions([require('JPCGTransform').instance()])
var view = require('UIView').alloc().init()
view.setTransform({a:1, b:0, c:0, d:1, tx:0, ty:100})

The param typeEncoding is value of @encode(structType):

typedef struct CustomStruct {
    int num;
    char *name;
} CustomStruct;

NSLog(@"%s", @encode(CGRect))   //{CGRect={CGPoint=dd}{CGSize=dd}}
NSLog(@"%s", @encode(CGAffineTransform))    //{CGAffineTransform=dddddd}
NSLog(@"%s", @encode(CustomStruct));    //{CustomStruct=i*}

##Add JS methods

The -main: method in JPExtension will be executed when the extension added to JPEngine, so we can add JS methods in -main:.

The 4 formatXXX methods are used for tranlate types through OC and JS, use -formatPointerJSToOC: / -formatJSToOC: to convert params from JS to OC, use -formatPointerOCToJS: / -formatOCToJS: to convert return value from OC to JS. Example:

@interface JPMemory : JPExtension
@end

@implementation JPMemory
- (void)main:(JSContext *)context
{
    context[@"malloc"] = ^id(size_t size) {
        void *m = malloc(size);
        return [self formatPointerOCToJS:m];
    };

    context[@"free"] = ^id(JSValue *jsVal) {
        void *m = [self formatPointerJSToOC:jsVal];
        free(m)
    };
}
@end

Now we can use malloc() and free() in JS:

require('JPEngine').addExtensions([require('JPMemory').instance()])
var m = malloc(1024)
free(m)
Clone this wiki locally