27
2017
09

ios ——JS 与OC混编

ios7之后,ios中加入了JavaScriptCore框架。该框架让Objective-C和JavaScript代码直接的交互变得更加的简单方便。

一、JSContext 与 JSValue

JSContext是OC与js交互的中间上下文,用于相互转化。
在iOS框架中,凡是带session或者context后缀的,这种类一般自己不干活,作用一般都是两个:1.管理其他类,帮助他们搭建沟通桥梁,好处就是解耦 2.负责帮助我们管理复杂环境下的内存
context与session不同之处是:session一般与硬件打交道,例如摄像头捕捉ARSession,网卡的调用NSURLSession等使用的都是session后缀。没有硬件参与,一般用context,如绘图上下文,自定义转场上下文等。

JSValue则可以说是JavaScript和Object-C值之间互换的桥梁,它提供了多种方法可以方便地把JavaScript数据类型转换成Objective-C,或者是转换过去。

二、OC 调用js代码

JSContext *context = [JSContext new];
JSValue *result = [context evaluateScript:@"1 + 2"];
    NSLog(@"%.2f",[result toDouble]);

三、 OC调用JS 的函数

 //先定义一句js上下文,带有sum函数
    JSContext *context = [JSContext new];
    NSString *js = @"function sum(a,b) {return a+b;}"; [context evaluateScript:js]; JSValue *sum = context[@"sum"];
    JSValue *result = [sum callWithArguments:@[@1,@2]];
    NSLog(@"%.2f",[result toDouble]);

四、在OC中js 中报错

如果js代码报错,项目中是无法体现的,所以要进行异常处理

 JSContext *context = [JSContext new];

    context.exceptionHandler = ^(JSContext *context, JSValue *exception) {

        NSLog(@"%@",exception);
    };

    [context evaluateScript:@"a.b = 123"];

五、block 与 js 进行互动

JSContext *context = [JSContext new];

    //block 与 js 进行互动时, block里面不要调用外边oc的变量
    context[@"sum"]=^(int a, int b) {

        //想在这里拿到contextz
        //JSContext *ctx = [JSContext currentContext];

        return a + b;
    };

    JSValue *result = [context evaluateScript:@"sum(1,2)"];
    NSLog(@"%.2f",[result toDouble]);

六、 给js中添加对象

创建Point3D类,利用协议

Point3D.h文件

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

@protocol Point3DExport <JSExport>

@property double x;
@property double y;
@property double z;

-(double)length;

@end


@interface Point3D : NSObject<Point3DExport>{
    JSContext *context;
}

-(id)initWithContext:(JSContext *)ctx;

@end

Point3D.m文件

#import "Point3D.h"

@implementation Point3D

@synthesize z;

@synthesize y;

@synthesize x;

-(id)initWithContext:(JSContext *)ctx{

    if (self =[super init]) {
        context = ctx;
        context[@"Point3D"] = [Point3D new];

    }

    return self;

}

-(double)length {

    return sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
}

@end

调用

JSContext *context = [JSContext new];
    Point3D *point3D = [[Point3D alloc] initWithContext:context];
    point3D.x = 1;
    point3D.y = 2;
    point3D.z = 3;
    context[@"point3D"] = point3D;
    NSString *script = @"point3D.x = 2;point3D.y = 2;point3D.length()";
    JSValue *result = [context evaluateScript:script];
     NSLog(@"%.2f",[result toDouble]);

当执行 context[@”point3D”] = point3D;时,相当于通过OC往js中添加point3D对象,但是js中并没有point3D class,只是把对象塞了过来。

七、OC 调用js 文件

创建test.js

这里写图片描述

var foo = function(a) {
    return "Hello Oc,I'm foo in JS."+a;
};

function bar(a) {
    return "Hello Oc,I'm bar in JS."+a;
};

foo(123);
bar(123);

console.log(foo(123));

此时console不能打印在xcode控制台
因此要创建Console类来重写打印方法

Console.h


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

@protocol ConsoleExport <JSExport>

- (void)log;

@end

@interface Console : NSObject <ConsoleExport>{

    JSContext *context;
}

-(id)initWithContext:(JSContext *)ctx;

@end

Console.m



#import "Console.h" @implementation Console  -(id)initWithContext:(JSContext *)ctx{ if (self =[super init]) { context = ctx; context[@"Console"] = [Console new]; } return self; } -(void)log { //所有的参数的数组 NSArray *args = [JSContext currentArguments]; NSLog(@"%@",[args componentsJoinedByString:@","]); } @end 

调用

JSContext *context = [JSContext new];

    context.exceptionHandler = ^(JSContext *context, JSValue *exception) {

        NSLog(@"%@",exception);
    };

    context[@"console"] = [[Console alloc]initWithContext:context];

    [self loadScriptWithContext:context WithFileName:@"test.js"];

demo代码下载地址

上一篇:解决RadioButton 在某些机器上不能居中显示 下一篇:Kotlin之Lambda表达式原理及应用