JavaScript Core binding

//
//  SecondViewController.m
//  Js_And_Object_C
//
//  Created by yeyuanxiang on 16/6/1.
//  Copyright © 2016年 KuYu_YX. All rights reserved.
//

#import "SecondViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import "Person.h"
@interface SecondViewController ()

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    [self test9];
}

//基本类型的转化
-(void)test1
{
    //初始化JS环境
    JSContext *context = [[JSContext alloc] init];
    JSValue *jsValue = [context evaluateScript:@"21+7"];
    int iVar = [jsValue toInt32];
    NSLog(@"JSValue: %@, int: %d", jsValue, iVar);
}

//存储变量
-(void)test2
{
    JSContext *context = [[JSContext alloc] init];
    [context evaluateScript:@"var arr = [21.7,'helloJS']"];
    JSValue *jsArr = context[@"arr"];
    NSLog(@"JS Array: %@; Length: %@", jsArr, jsArr[@"length"]);
    
    jsArr[1] = @"blog";
    jsArr[7] = @7 ;
    NSLog(@"JS Array: %@; Length: %d", jsArr, [jsArr[@"length"] toInt32]);
    
    NSArray *nsArr = [jsArr toArray];
    NSLog(@"NSArray: %@", nsArr);
    
}


//方法的转换
-(void)test3
{
    /*
     各种数据类型可以转换,Objective-C的Block也可以传入JSContext中当做JavaScript的方法使用。比如在前端开发中常用的log方法,虽然JavaScritpCore没有自带(毕竟不是在网页上运行的,自然不会有window、document、console这些类了),仍然可以定义一个Block方法来调用NSLog来模拟:
     */
    
    JSContext *context = [[JSContext alloc] init];
    context[@"log"] = ^(){
        NSLog(@"++++++++++++++++");
        
        //类方法来获取参数列表
        NSArray *args = [JSContext currentArguments];
        for (JSValue *jsValue in args) {
            
            NSLog(@"%@",jsValue);
        }
    };
    
    
    //当前调用该方法的对象
    JSValue *this = [JSContext currentThis];
    NSLog(@"this:    %@",this);
    
    
    [context evaluateScript:@"log('ider', [7, 21], { hello:'world', js:100 });"];
    
//    NSLog(@"%@",value);
    
}


/*
 Block可以传入JSContext作方法,但是JSValue没有toBlock方法来把JavaScript方法变成Block在Objetive-C中使用。毕竟Block的参数个数和类型已经返回类型都是固定的。虽然不能把方法提取出来,但是JSValue提供了- (JSValue *)callWithArguments:(NSArray *)arguments;方法可以反过来将参数传进去来调用方法。
 */

-(void)test4
{
    JSContext *context = [[JSContext alloc] init];
    [context evaluateScript:@"function add(a, b) { return a + b; }"];
    JSValue *add = context[@"add"];
    NSLog(@"Function:%@",add);
    
    
    JSValue *sum = [add callWithArguments:@[@(7),@(2)]];
    NSLog(@"Sum:%d",[sum toInt32]);
    
    
    /*
     JSValue还提供- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;让我们可以直接简单地调用对象上的方法。只是如果定义的方法是全局函数,那么很显然应该在JSContext的globalObject对象上调用该方法;如果是某JavaScript对象上的方法,就应该用相应的JSValue对象调用。
     */
}



//异常处理
-(void)test5
{
    /*
     Objective-C的异常会在运行时被Xcode捕获,而在JSContext中执行的JavaScript如果出现异常,只会被JSContext捕获并存储在exception属性上,而不会向外抛出。时时刻刻检查JSContext对象的exception是否不为nil显然是不合适,更合理的方式是给JSContext对象设置exceptionHandler,它接受的是^(JSContext *context, JSValue *exceptionValue)形式的Block。其默认值就是将传入的exceptionValue赋给传入的context的exception属性:
     */
    
    
//    ^(JSContext *context, JSValue *exceptionValue) {
//        context.exception = exceptionValue;
//    };
    
    
    
    //或者
    JSContext *context = [[JSContext alloc] init];
    context.exceptionHandler = ^(JSContext *con, JSValue *exception){
      
        NSLog(@"exception:  %@",exception);
        con.exception = exception ;
    };
    
    
    [context evaluateScript:@"ider.zheng=2"];
    
    /*
     使用Block的注意事项
     从之前的例子和介绍应该有体会到Block在JavaScriptCore中起到的强大作用,它在JavaScript和Objective-C之间的转换 建立起更多的桥梁,让互通更方便。但是要注意的是无论是把Block传给JSContext对象让其变成JavaScript方法,还是把它赋给exceptionHandler属性,在Block内都不要直接使用其外部定义的JSContext对象或者JSValue,应该将其当做参数传入到Block中,或者通过JSContext的类方法+ (JSContext *)currentContext;来获得。否则会造成循环引用使得内存无法被正确释放。
     
     比如上边自定义异常处理方法,就是赋给传入JSContext对象con,而不是其外创建的context对象,虽然它们其实是同一个对象。这是因为Block会对内部使用的在外部定义创建的对象做强引用,而JSContext也会对被赋予的Block做强引用,这样它们之间就形成了循环引用(Circular Reference)使得内存无法正常释放。
     对于JSValue也不能直接从外部引用到Block中,因为每个JSValue上都有JSContext的引用 (@property(readonly, retain) JSContext *context;),JSContext再引用Block同样也会形成引用循环。
     
     */
}



/*
 前面十分的简单方便而且高效,不过也仅限于数值型、布尔型、字符串、数组等这些基础类型。本文将扩展到更复杂的类型,介绍一下该强大的框架是如何让Objective-C对象和JavaScript对象进行直接互通的。
 */

//为了方便起见,以下所有代码中的JSContext对象都会添加如下的log方法和eventHandler:
-(void)test6
{
    JSContext *context = [[JSContext alloc] init];
    context.exceptionHandler = ^(JSContext *con, JSValue *exception) {
        NSLog(@"%@", exception);
        con.exception = exception;
    };
    
    context[@"log"] = ^() {
        NSArray *args = [JSContext currentArguments];
        for (id obj in args) {
            NSLog(@"%@",obj);
        }
    };
    
    
    
    //键值对编程—Dictionary
    /*
     JSContext并不能让Objective-C和JavaScript的对象直接转换,毕竟两者的面向对象的设计方式是不同的:前者基于class,后者基于prototype。但所有的对象其实可以视为一组键值对的集合,所以JavaScript中的对象可以返回到Objective-C中当做NSDictionary类型进行访问。
     */
    
    
    JSValue *obj =[context evaluateScript:@"var jsObj = { number:7, name:'Ider' }; jsObj"];
    NSLog(@"%@, %@", obj[@"name"], obj[@"number"]);
    NSDictionary *dic1 = [obj toDictionary];
    NSLog(@"%@, %@", dic1[@"name"], dic1[@"number"]);
    
    
    
    //同样的,NSDicionary和NSMutableDictionary传入到JSContext之后也可以直接当对象来调用:
    NSDictionary *dic = @{@"name": @"Ider", @"#":@(21)};
    context[@"dic"] = dic;
    [context evaluateScript:@"log(dic.name, dic['#'])"];
}


//语言穿梭机—JSExport协议
-(void)test7
{
    /*
     JavaScript可以脱离prototype继承完全用JSON来定义对象,但是Objective-C编程里可不能脱离类和继承了写代码。所以JavaScriptCore就提供了JSExport作为两种语言的互通协议。JSExport中没有约定任何的方法,连可选的(@optional)都没有,但是所有继承了该协议(@protocol)的协议(注意不是Objective-C的类(@interface))中定义的方法,都可以在JSContext中被使用。语言表述起来有点绕,还是用例子来说明会更明确一点。
     */
    
    
    
    //首先建立一个Person类
    /*
     在代码中,定义了一个PersonProtocol,并让它继承了神秘的JSExport协议,在新定义的协议中约定urls属性和fullName方法。之后又定义了Person类,除了让它实现PersonProtocol外,还定义了firstName和lastName属性。而fullName方法返回的则是两部分名字的结合。
     */
    
    
    JSContext *context = [[JSContext alloc] init];
    context.exceptionHandler = ^(JSContext *con, JSValue *exception) {
        NSLog(@"%@", exception);
        con.exception = exception;
    };
    
    context[@"log"] = ^() {
        NSArray *args = [JSContext currentArguments];
        for (id obj in args) {
            NSLog(@"%@",obj);
        }
    };
    
    Person *person = [[Person alloc] init];
    context[@"p"] = person ;
    person.firstName = @"Ider" ;
    person.lastName = @"Zheng" ;
    person.urls = @{@"site": @"http://www.iderzheng.com"};
    
    [context evaluateScript:@"log(p.fullName());"];
    [context evaluateScript:@"log(p.firstName);"];
    [context evaluateScript:@"log(p.lastName);"];
    
    [context evaluateScript:@"log('size:',p.urls.size, 'blog:', p.urls.blog)"];
    [context evaluateScript:@"p.urls = {blog:'http://blog.iderzheng.com'}"];
    [context evaluateScript:@"log('-------AFTER CHANGE URLS-------')"];
    [context evaluateScript:@"log('site:', p.urls.site, 'blog:', p.urls.blog);"];
    
    
    NSLog(@"%@", person.urls);
}



//OC调用JS方法
-(void)test9
{
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"js"];
    NSString *indexScript = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    JSContext *context = [[JSContext alloc] init];
    [context evaluateScript:indexScript];
    
    
    JSValue *function = context[@"factorial"];
    JSValue *result = [function callWithArguments:@[@(10)]];
    
    NSLog(@"factorial(10) = %d",[result toInt32]);
}

//JS调用OC方法
-(void)test8
{
    JSContext *context = [[JSContext alloc] init];
    //    context[@"creatUIColor"] = ^(NSDictionary *rgbColor){
    //
    //        return [UIColor colorWithRed:([rgbColor[@"red"] floatValue] / 255.0)
    //                               green:([rgbColor[@"green"] floatValue] / 255.0)
    //                               blue:([rgbColor[@"blue"] floatValue] / 255.0)
    //                               alpha:1];
    //    };
    //
    //    JSValue *color = [context evaluateScript:@"makeUIColor({red: 150, green: 150, blue: 200})"];
    //
    //    NSLog(@"color:%@",[color toObject]);
    
    context[@"callback"] = ^{
        
        JSValue *object = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
        object[@"x"] = @"2";
        object[@"y"] = @"3" ;
        return object ;
    };
    
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值