OC与JS交互之JavaScriptCore


JavaScriptCore提供了JavaScript和Objective-C桥接的Obj-C API。JavaScriptCore提供了让我们脱离UIWebView执行JavaScript脚本的能力,以及使用现代的Objective-C语法(例如Blocks和下标)在Objective-C和JavaScript之间无缝的传递值或者对象。借助JavaScriptCore,我们只需要很少的代码就可以完成OC与JS的交互通信,下面让我们一睹它的风采。同样,这篇文章会用JavaScriptCore有关API重写

 

一、JavaScriptCore概述

使用JavaScriptCore需要导入头文件"#import <JavaScriptCore/JavaScriptCore.h>",进入头文件我们会看到里面的类不多,只有下面5个:

1
2
3
4
5
#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"

JSContext: 代表JavaScript的运行环境,创建JSContext后,可以来执行JavaScript代码。

JSValue: 代表JavaScript实体,一个JSValue可以是JavaScript中的任意类型:字符串和数字;数组、对象和方法;甚至错误和特殊的 JavaScript 值诸如 null 和 undefined。任何JSContext的值都被包裹在一个JSValue对象中。

JSManagedValue: 本质上是一个JSValue,用来处理内存管理中的一些特殊情形,它能帮助OC引用技术和JS垃圾回收这两种内存管理机制之间进行正确的转换。

JSExport: 这是一个协议,可以用这个协议来将原生对象导出给JavaScript,这样原生对象的属性或方法就成为了JavaScript的属性或方法。

JSVirtualMachine: 代表一个对象空间,拥有自己的堆结构和垃圾回收机制,是运行JS代码的基础。大部分情况下不需要和它直接交互,除非要处理一些特殊的多线程或者内存管理问题。

 

二、JavaScriptCore深入

1. 方法调用

a. OC调用JS

1
2
3
4
5
6
7
8
//使用UIWebView执行js脚本的方法
- (nullable  NSString   *)stringByEvaluatingJavaScriptFromString:( NSString   *)script;
 
//使用JSContext执行js脚本的方法
- (JSValue *)evaluateScript:( NSString   *)script;
 
//使用JSValuet执行js脚本的方法
- (JSValue *)callWithArguments:( NSArray   *)arguments;

b. JS调用OC

有两种方式:block和JSExport协议

通过block可以直接讲某个功能的函数,注入给JSContext,使其调用,但要注意内存泄露

通过继承JSExport协议,可以将OC的方法,属性注入给JSContext,然后调用

 

2. 错误处理

当JavaScript运行时出现异常,会回调JSContext的exceptionHandler中设置的Block,然后在OC端进行错误处理

1
2
3
context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
       NSLog (@ "JS Error: %@" , exception);
};

 

3. 内存管理 

Objective-C的内存管理机制是引用计数,JavaScript的内存管理机制是垃圾回收。在大部分情况下,JavaScriptCore能做到在这两种内存管理机制之间无缝无错转换,但也有少数情况需要使用到JSManagedValue对象解决,后面会给出对应链接。

 

三、使用JavaScriptCore重写

 沿用之前的示例,其他地方均无改动,只修改了两边交互的相关代码:

OC端:

1. 初始化JScontext

1
self .jsContext = [ self .webView valueForKeyPath:@ "documentView.webView.mainFrame.javaScriptContext" ];

2. 注入JS代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__block typeof( self ) weakSelf =  self ;
//JS调用OC方法列表
self .jsContext[@ "showMobile" ] = ^ {
     dispatch_async(dispatch_get_main_queue(), ^{
         [weakSelf showMsg:@ "我是下面的小红 手机号是:18870707070" ];
     });
};
 
self .jsContext[@ "showName" ] = ^ ( NSString   *name) {
     dispatch_async(dispatch_get_main_queue(), ^{
         NSString   *info = [ NSString   stringWithFormat:@ "你好 %@, 很高兴见到你" ,name];
         [weakSelf showMsg:info];
     });
};
 
void   (^_showSendMsg) ( NSString   *num,  NSString   *msg) = ^ ( NSString   *num,  NSString   *msg) {
     dispatch_async(dispatch_get_main_queue(), ^{
         NSString   *info = [ NSString   stringWithFormat:@ "这是我的手机号: %@, %@ !!" ,num,msg];
         [ self   showMsg:info];
     });
};
 
[ self .jsContext setObject:_showSendMsg forKeyedSubscript:@ "showSendMsg" ];

3. 执行JS端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//OC调用JS方法列表
- ( IBAction )btnClick:(UIButton *)sender {
     if   (sender.tag == 123) {
         //使用jsContext
         [ self .jsContext evaluateScript:@ "alertMobile()" ];
     }
     
     if   (sender.tag == 234) {
         //使用webView
         [ self .webView stringByEvaluatingJavaScriptFromString:@ "alertName('小红')" ];
     }
     
     if   (sender.tag == 345) {
         //使用jsValue
         JSValue *jsValue = [ self .jsContext objectForKeyedSubscript:@ "alertSendMsg" ];
         [jsValue callWithArguments:@[@ "18870707070" ,@ "周末爬山真是件愉快的事情" ]];
     }
}

 

JS端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//提供给OC调用JS的方法列表
function   alertMobile() {
     alert( '我是上面的小黄 手机号是:13300001111' )
}
 
function   alertName(msg) {
     alert( '你好 '   + msg +  ', 我也很高兴见到你' )
}
 
function   alertSendMsg(num,msg) {
     alert( '这是我的手机号:'   + num +  ','   + msg +  '!!' )
}
 
//JS响应方法列表
function   btnClick1() {
     showMobile()
}
 
function   btnClick2() {
     showName( 'xiaohuang' )
}
 
function   btnClick3() {
     showSendMsg( '13300001111' 'Go Climbing This Weekend !!!' )
}

 

了解过JavaScriptCore的原理及核心文件,核心类的作用,再过来上手重写,已经没有什么什么阻碍了,但是仍然有需要注意的地方。因为JavaScript是单线程的,在JS调用OC的代码都是在线程中执行的,所以和界面相关操作我们需要切换到主线程来刷新,其他流程和之前保持一致,学习这一部分参考了很多其他资料,文章后面给出了有关JavaScriptCore的介绍和实现原理解析的文章链接,有兴趣的同学可以传送之深入学习

 

四、后记

苹果的技术每年都会更新,在JavaScript这一块,每年也会出现新的惊喜,iOS8发布的时候,苹果又推出了WKWebView,对之前的UIWebView进行了一次脱胎换骨的重构(将UIWebView和UIWebViewDelegate重构成了14个类和3个协议),功能也更加完善和强大,稳定性和性能也明显提高。之前看到过一篇文章,详细介绍了WKWebView的相关API,对我了解这一模块提供了很大的帮助,后面我也系统的看完了整个WKWebView的API,受益匪浅,看的时候,我没有直接过去看这篇文章,而是先自己通读API然后对比这篇文章,查看理解方面的出入,同时也加深了印象,同学们也可以借鉴这种方式。下一篇文章,我们使用WKWebView的相关API来完成这个示例


原文地址:

http://www.cnblogs.com/markstray/p/5757255.html


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值