iOS10iOS Developer程序员

初识JavaScriptCore

2016-08-26  本文已影响460人  GiantAxe77

JavaScriptCore介绍

JavaScriptCore概述

JSContext/JSValue

    JSContext *context = [[JSContext alloc] init];
    [context evaluateScript:@"var num = 1 + 2"];
    [context evaluateScript:@"var names = ['Giant', 'Axe', 'GA']"];
    [context evaluateScript:@"var triple = function(value) { return value * 3 }"];
    JSValue *tripleNum = [context evaluateScript:@"triple(num)"];
JavaScript Type JSValue Method Objective-C Type Swift Type
string toString NSString String!
boolean toBool BOOL Bool
number toNumber,toDouble,toInt32,toUInt32 NSNumber,double,int32_t,uint32_t NSNumber!,Double,Int32,UInt32
Date toDate NSDate NSDate!
Array toArray NSArray [AnyObject]!
Object toDictionary NSDictionary [NSObject : AnyObject]!
Object toObject,toObjectOfClass: custom type custom type
NSLog(@"Tripled: %d", [tripleNum toInt32]);
// Tripled: 9

下标值

JSValue *names = context[@"names"];
JSValue *initialName = names[0];
NSLog(@"The first name: %@", [initialName toString]);
// The first name: Giant

调用方法

JSValue *tripleFunction = context[@"triple"];
JSValue *result = [tripleFunction callWithArguments:@[@5]];
NSLog(@"Five tripled: %d", [result toInt32]);

错误处理

context.exceptionHandler = ^(JSContext *context, JSValue *exception) { 
  NSLog(@"JS Error: %@", exception);
};
[context evaluateScript:@"function multiply(value1, value2) { return value1 * value2 "];
// JS Error: SyntaxError: Unexpected end of script

JavaScript调用

oc调js

function printHello() {
}
    // 取出js路径
    NSString *scriptPath = [[NSBundle mainBundle] pathForResource:@"hello" ofType:@"js"];
    
    // UTF8编码
    NSString *scriptString = [NSString stringWithContentsOfFile:scriptPath encoding:NSUTF8StringEncoding error:nil];
    
    // 初始化JSContext
    JSContext *context = [[JSContext alloc] init];
    
    // 执行JavaScript脚本
    [context evaluateScript:scriptString];
    
    // 取出printHello函数,保存到JSValue中
    JSValue *function = self.context[@"printHello"];
    
    // 调用(如果JSValue是一个js函数,可以用callWithArguments来调用,参数是一个数组,如果没有参数则传入空数组@[])
    [function callWithArguments:@[]];

js调oc

JS调用OC有两个方法:block和JSExport protocol。
    // 初始化JSContext
    self.context = [[JSContext alloc] init];
    
    // 定义block保存到context中
    self.context[@"add"] = ^(NSInteger a, NSInteger b) {
        NSLog(@"addNum : %@", @(a + b));
    };
    
    // 执行javaScript
    [self.context evaluateScript:@"add(2,3)"];
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>

@protocol JSTestDelegate <JSExport>

// 测试无参数
- (void)testNoPara;
// 测试一个参数
- (void)testOnePara:(NSString *)msg;
// 测试两个参数
- (void)testTwoPara:(NSString *)msg1 secondPara:(NSString *)msg2;

@end

@interface testJSObject : NSObject <JSTestDelegate>

@end
#import "testJSObject.h"

@implementation testJSObject

- (void)testNoPara
{
    NSLog(@"no para");
}

- (void)testOnePara:(NSString *)msg
{
    NSLog(@"one para");
}

- (void)testTwoPara:(NSString *)msg1 secondPara:(NSString *)msg2
{
    NSLog(@"two para");
}

@end

    // 创建JSContext
    self.context = [[JSContext alloc] init];

    //设置异常处理 
    self.context.exceptionHandler = ^(JSContext *context,JSValue *exception) {
        [JSContext currentContext].exception = exception; 
        NSLog(@"exception:%@",exception);                 
    };
    
    // 将testObj添加到context中
    testJSObject *testObj = [testJSObject new];
    self.context[@"testObject"] = testObj;
   
    NSString *jsStr1 = @"testObject.testNoPara()";
    NSString *jsStr2 = @"testObject.testOnePara()";
    [self.context evaluateScript:jsStr1];
    [self.context evaluateScript:jsStr2];
打印结果

内存管理陷阱

在block内捕获JSContext

    self.context[@"getVersion"] = ^{
        NSString *versionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
        
        versionString = [@"version " stringByAppendingString:versionString];
        
        JSContext *context = [JSContext currentContext]; // 这里不要用self.context
        JSValue *version = [JSValue valueWithObject:versionString inContext:context];
        
        return version;
    };

JSManagedValue

#import <UIKit/UIKit.h>
#import <JavaScriptCore/JavaScriptCore.h>

@interface MyAlertView : UIAlertView

- (id)initWithTitle:(NSString *)title
            message:(NSString *)message
            success:(JSValue *)successHandler
            failure:(JSValue *)failureHandler
            context:(JSContext *)context;

@end
    self.context[@"presentNativeAlert"] = ^(NSString *title,
                                            NSString *message,
                                            JSValue *success,
                                            JSValue *failure) {
        JSContext *context = [JSContext currentContext];
        MyAlertView *alertView = [[MyAlertView alloc] initWithTitle:title
                                                            message:message
                                                            success:success
                                                            failure:failure
                                                            context:context];
        [alertView show];
    };
#import "MyAlertView.h"

@interface MyAlertView() <UIAlertViewDelegate>
@property (strong, nonatomic) JSContext *ctxt;
@property (strong, nonatomic) JSMagagedValue *successHandler;
@property (strong, nonatomic) JSMagagedValue *failureHandler;
@end

@implementation MyAlertView

- (id)initWithTitle:(NSString *)title
            message:(NSString *)message
            success:(JSValue *)successHandler
            failure:(JSValue *)failureHandler
            context:(JSContext *)context {
    
    self = [super initWithTitle:title
                        message:message
                       delegate:self
              cancelButtonTitle:@"No"
              otherButtonTitles:@"Yes", nil];
    
    if (self) {
        _ctxt = context;
        
        _successHandler = [JSManagedValue managedValueWithValue:successHandler];
        // A JSManagedValue by itself is a weak reference. You convert it into a conditionally retained
        // reference, by inserting it to the JSVirtualMachine using addManagedReference:withOwner:
        [context.virtualMachine addManagedReference:_successHandler withOwner:self];
        
        _failureHandler = [JSManagedValue managedValueWithValue:failureHandler];
        [context.virtualMachine addManagedReference:_failureHandler withOwner:self];
    }
    return self;
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex == self.cancelButtonIndex) {
        JSValue *function = [self.failureHandler value];
        [function callWithArguments:@[]];
    } else {
        JSValue *function = [self.successHandler value];
        [function callWithArguments:@[]];
    }
    
    [self.ctxt.virtualMachine removeManagedReference:_failureHandler withOwner:self];
    [self.ctxt.virtualMachine removeManagedReference:_successHandler withOwner:self];
}    

@end

参考资料

上一篇 下一篇

猜你喜欢

热点阅读