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来完成这个示例

戳这里:本文的DEMO地址欢迎star

参考资料(戳这里):

>  http://nshipster.cn/javascriptcore/

>  https://hjgitbook.gitbooks.io/ios/content/04-technical-research/04-javascriptcore-note.html

>  JavaScriptCore实现的原理解析系列

JavaScriptCore-b的更多相关文章

  1. How Javascript works (Javascript工作原理) (二) 引擎,运行时,如何在 V8 引擎中书写最优代码的 5 条小技巧

    个人总结: 一个Javascript引擎由一个标准解释程序,或者即时编译器来实现. 解释器(Interpreter): 解释一行,执行一行. 编译器(Compiler): 全部编译成机器码,统一执行. ...

  2. iOS引入JavaScriptCore引擎框架(一)

    JavaScriptCore引擎     我们都知道WebKit是个渲染引擎,简单来说负责页面的布局,绘制以及层的合成,但是WebKit工程中不仅仅有关于渲染相关的逻辑,也集成了默认的javascri ...

  3. 判断js引擎是javascriptCore或者v8

    来由   纯粹的无聊,一直在搜索JavaScriptCore和SpiderMonkey的一些信息,却无意中学习了如何在ios的UIWebView中判断其js解析引擎的方法: if (window.de ...

  4. DDD 领域驱动设计-看我如何应对业务需求变化,愚蠢的应对?

    写在前面 阅读目录: 具体业务场景 业务需求变化 "愚蠢"的应对 消息列表实现 消息详情页实现 消息发送.回复.销毁等实现 回到原点的一些思考 业务需求变化,领域模型变化了吗? 对 ...

  5. CSS3 3D立方体效果-transform也不过如此

    CSS3系列已经学习了一段时间了,第一篇文章写了一些css3的奇技淫巧,原文戳这里,还获得了较多网友的支持,在此谢过各位,你们的支持是我写文章最大的动力^_^. 那么这一篇文章呢,主要是通过一个3D立 ...

  6. DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(3)

    上一篇:<DDD 领域驱动设计-谈谈 Repository.IUnitOfWork 和 IDbContext 的实践(2)> 这篇文章主要是对 DDD.Sample 框架增加 Transa ...

  7. DDD 领域驱动设计-两个实体的碰撞火花

    上一篇:<DDD 领域驱动设计-领域模型中的用户设计?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sample(代码已更新) 在 ...

  8. node中的Stream-Readable和Writeable解读

    在node中,只要涉及到文件IO的场景一般都会涉及到一个类-Stream.Stream是对IO设备的抽象表示,其在JAVA中也有涉及,主要体现在四个类-InputStream.Reader.Outpu ...

  9. C#~异步编程再续~await与async引起的w3wp.exe崩溃-问题友好的解决

    返回目录 关于死锁的原因 理解该死锁的原因在于理解await 处理contexts的方式,默认的,当一个未完成的Task 被await的时候,当前的上下文将在该Task完成的时候重新获得并继续执行剩余 ...

随机推荐

  1. Apache Shiro 集成-Cas

    http://blog.csdn.net/peterwanghao/article/details/8825008 Shiro集成CAS是在1.2版本里新增的功能. Shiro-cas模块将应用作为C ...

  2. How to easily concatenate text based on criteria in Excel? 如何将Excel中的文本按条件合并

    To combine text with the unique ID numbers, you can extract the unique values first and then create ...

  3. android常见错误-Installation error: INSTALL_FAILED_INSUFFICIENT_STORAGE

    在andorid进行调试的过程中,出现下面的错误: 解决方法: 修改一下应用程序描述符: <manifest xmlns:android="http://schemas.android ...

  4. 【web开发学习笔记】ibatis学习总结

    ibatis学习总结 ibatis数据库配置文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCT ...

  5. VS2012执行Cocos2d-xTest案例载入失败解决方式

    编译cocos2d-x,一直提示载入失败 通过搜索,解决方式例如以下: 第一步,通过命令提示行工具进入VS安装文件夹下的%VS2012home%Common7\IDE 第二部,运行devenv.exe ...

  6. 数据结构与算法/leetcode/lintcode题解

    http://algorithm.yuanbin.me/zh-hans/index.html

  7. (转载)myeclipse项目名称重命名

    myeclipse项目名称重命名 实例1 今天晚上在做一个jsp唱片显示的实例,myeclipse项目名称原本想写music结果写成了musci.这就需要项目名称的重命名,单纯的使用 “重构--> ...

  8. java String的比较,BOX装箱拆箱,以及面向对象的小代码

    package cn.hncu.day2; public class StringDemo { public static void main(String[] args) { String str1 ...

  9. Java基础知识强化之网络编程笔记08:TCP之客户端键盘录入服务器控制台输出

    1. 客户端: package cn.itcast_08; import java.io.BufferedReader; import java.io.BufferedWriter; import j ...

  10. Bash判断文件是否存在

    #!/bin/bash if [ -f filename ]; then echo 'file exist' else echo 'file not exist' fi