IOS开发笔记之JavaScriptCore.framework

JavaScriptCore.framework,是Apple在IOS7.0系统中新加入的一个框架,通过这个框架,Object-c与JavaScript的交互变得简单起来。

(如果对JavaScript不是很熟的可以看下这个网站,http://www.w3school.com.cn/js/js_variables.asp)

先来了解下JavaScriptCore.framework。下图是该框架的Header文件。


Object-C调用JavaScript

JSContext/JSValue

JSContext是运行JavaScript代码的环境,一个JSContext是一个全局环境的实例。通过JSContext就可以运行JavaScript代码,可以创建变量,定义方法等。
下面是一个简单的调用。

    JSContext *context = [[JSContext alloc] init];
    //数字和方法
    [context evaluateScript:@"var num = 5 + 3"];
    [context evaluateScript:@"var newNum = function(value) { return value * 5 }"];
    JSValue *tripleNum = [context evaluateScript:@"newNum(num)"];
    int result = [tripleNum toInt32];
    NSLog(@"tripleNum = %d",result);
    //字符串
    [context evaluateScript:@"var name = 'test'"];
    JSValue *name = [context evaluateScript:@"name"];
    NSString * ocName = [name toString];
    NSLog(@"ocName = %@",ocName);
    //数组
    [context evaluateScript:@"var ary_Name = ['ss','xx','tt']"];
    JSValue * ary_Name = context[@"ary_Name"];
    JSValue * jsv_name = ary_Name[2];
    NSString * name_three = [jsv_name toString];
    NSLog(@"name_three = %@",name_three);

任何出自JSContext的值都被存放在一个JSValue对象中。
JSValue  包括一系列方法用于访问其可能的值以保证有正确的 Foundation 类型,包括:


对 JSContext 和 JSValue 实例使用下标的方式我们可以很容易地访问我们之前创建的 context 的任何值。JSContext 需要一个字符串下标,而 JSValue 允许使用字符串或整数标来得到里面的对象和数组

调用方法

我们可以在Object-c或者swift中使用Foundation类型作为参数来调用JavaScript中的函数,比如上段代码中的newNum函数

    //方法调用
    JSValue * newNumFunction = context[@"newNum"];
    JSValue * newNumResult = [newNumFunction callWithArguments:@[@5]];
    result = [newNumResult toUInt32];
    NSLog(@"result = %d",result);

错误处理

在JSContext中, exceptionHandler是一个接收JSContext引用和异常本身的回调处理,我们可以观察和记录语法,类型以及运行时错误。

    //错误记录
    context.exceptionHandler = ^(JSContext * context, JSValue * exception){
        NSLog(@"js error = %@",exception);
    };
以上是我们在Object-c中调用JavaScript的变量和方法。

JavaScript调用Object-c

让  JSContext  访问我们的本地客户端代码的方式主要有两种:block 和  JSExport  协议

block

一个简单的JS调用Object-c的计算方法
    context[@"simpleCalculate"] = ^(NSString * inputString, int numA, int numB){
        NSString * result = @"wrong calculate symbol";
        if ([inputString isEqualToString:@"+"]) {
            result = [NSString stringWithFormat:@"%d",numA + numB];
        }else if ([inputString isEqualToString:@"-"]){
            result = [NSString stringWithFormat:@"%d",numA - numB];
        }else if ([inputString isEqualToString:@"*"]){
            result = [NSString stringWithFormat:@"%d",numA * numB];
        }else if ([inputString isEqualToString:@"/"]){
            result = [NSString stringWithFormat:@"%d",numA / numB];
        }
        return result;
    };
    
    NSLog(@"%@",[context evaluateScript:@"simpleCalculate('*','5','3')"]);

试试修改UI层
    //试试修改OC的UI层
    UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setFrame:CGRectMake(100, 100, 200, 50)];
    [button setBackgroundColor:[UIColor orangeColor]];
    [self.view addSubview:button];
    
    context[@"changeTitle"] = ^(NSString * title){
        [button setTitle:title forState:UIControlStateNormal];
    };
    [context evaluateScript:@"changeTitle('我是测试按钮')"];

JSExport协议

JSExport是Object-c和JavaScript两种语言的互通协议,继承了该协议的协议都可以在JSContext中被使用。
下面是一个修改UIButton的title的协议,该协议继承了JSExport
@protocol UIButtonExport <JSExport>

- (void)setBackgroundColor:(UIColor *)color;
- (void)setTitle:(NSString *)title forState:(UIControlState)state;

@end

下面是这个协议的使用方法
    //试试修改OC的UI层
    UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setFrame:CGRectMake(100, 100, 200, 50)];
    [button setBackgroundColor:[UIColor orangeColor]];
    [self.view addSubview:button];
    
    context[@"changeTitle"] = ^(NSString * title){
        [button setTitle:title forState:UIControlStateNormal];
    };
    [context evaluateScript:@"changeTitle('我是测试按钮')"];
    
    //对已定义的类添加协议 需要引入#import <objc/runtime.h>
    class_addProtocol([UIButton class], @protocol(UIButtonExport));
    
    context[@"button"] = button;
    [context evaluateScript:@"button.setTitleForState('hello js','0')"];

注意,对于Object-c中多参数的方法,JavaScriptCore处理的方法是将Object-c方法每个部分都合并,将冒号移除且冒号后面的字母大写,上面代码最后一行的setTitleForState就是这样。如果希望换一个较短的方法名,可以调用 JSExportAs(PropertyName, Selector)这个宏。
JSExportAs(changeTitle, - (void)setTitle:(NSString *)title forState:(UIControlState)state);
    context[@"button"] = button;
//    [context evaluateScript:@"button.setTitleForState('hello js','0')"];
    [context evaluateScript:@"button.changeTitle('hello js','0')"];

一个简单的通过JavaScript获取当前时间并实时更新到UIButton的Title上的代码
    UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setFrame:CGRectMake(10, 100, 300, 50)];
    [button setBackgroundColor:[UIColor orangeColor]];
    button.titleLabel.font = [UIFont systemFontOfSize:12.0f];
    [button addTarget:self action:@selector(repeatsChange) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
- (void)repeatsChange{
    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(changeTitle) userInfo:nil repeats:YES];
    [timer fire];
}


- (void)changeTitle{
    
    UIButton * btn;
    for (UIButton * button in self.view.subviews) {
        if (button) {
            btn = button;
        }
    }
    
    JSContext * context = [[JSContext alloc]init];
    context[@"btn"] = btn;
    [context evaluateScript:@"var now = new Date()"];//JS获取当前时间
//    [context evaluateScript:@"var num = now.getSeconds()"];
    [context evaluateScript:@"btn.changeTitle(now,'0')"];
}
后续有了解的话继续补充

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值