JavaScriptCore in swift

JavaScriptCore是IOS7之后苹果悄悄推出的一个框架,用于Javascript与objective-c/swift互通。让Javascript开发者可以轻松愉快地用Javascript编写应用程序。

根据我学习的原则,新东西学习,就一起学吧,所以边学swift边学Javascript,于是就用swift来折腾折腾JavaScriptCore。

一、先看看JavaScriptCore框架的头文件:

1 #import "JSContext.h"
2 #import "JSValue.h"
3 #import "JSManagedValue.h"
4 #import "JSVirtualMachine.h"
5 #import "JSExport.h"
JSContext:Javascript的运行环境,一个JSContext就是一个Javascript的一个运行环境,也叫做作用域;个人理解,这个东西就是你有swift里的一个Javascript运行环境。
JSValue:JSContext里的不同的Javascript值都可以封闭在JSVslue的对象里,包括字符串、数值、数组、函数等,甚至还有Error以及null和undefined;同时这个类型的对象可以方便快速地转化为swift里常用的数据类型,如toBool()、toUInt32()、toArray()、toDictionary()等;简单地说就是Javascript中的数据类型与swift中的数据类型相互转化的一个中间数据类型   附:JavaScript与objective-c/swift中的数据类型对应表
 1    Objective-C type  |   JavaScript type
 2  --------------------+---------------------
 3          nil         |     undefined
 4         NSNull       |        null
 5        NSString      |       string
 6        NSNumber      |   number, boolean
 7      NSDictionary    |   Object object
 8        NSArray       |    Array object
 9         NSDate       |     Date object
10        NSBlock (1)   |   Function object (1)
11           id (2)     |   Wrapper object (2)
12         Class (3)    | Constructor object (3)
JSManagedValue:该类型主要是作为一个引用桥接,将JSValue转为JSManagedValue类型后,可以添加到JSVirtualMachine对象中,这样能够保证你在使用过程中JSValue对象不会被释放掉,当你不再需要该JSValue对象后,从JSVirtualMachine中移除该JSManagedValue对象,JSValue对象就会被释放并置空。
JSVirtualMachine:JSVirtualMachine就是一个用于保存弱引用对象的数组,加入该数组的弱引用对象因为会被该数组retain,所以保证了使用时不会被释放,当数组里的对象不再需要时,就从数组中移除,没有了引用的对象就会被系统释放;
JSExport:JSExport是一个协议,让JSContext运行环境中的JavaScript 可以识别该协议中定义的实例方法、类方法、属性等,让objective-c/swift与JavaScript能够自动交互;
二、框架的整体结构大概了解一二了,接下来动手写写代码
 var context:JSContext = JSContext()//JSContext就是一个JS运行环境
 1 context.evaluateScript("var number = 5 + 5")//往运行环境里加整形变量
 2         context.evaluateScript("var names = [‘Grace‘,‘Joe‘,‘Mike‘]")//数组
 3         context.evaluateScript("var triple = function(value){return value * 4}")//方法
 4         var tripleNumber:JSValue = context.evaluateScript("triple(number)")
 5         println("\(tripleNumber)")//40
 6         let ocnames:JSValue = context.objectForKeyedSubscript("names")//取出JS运行环境里的数组(为JSValue类型)
 7         var len = ocnames.objectForKeyedSubscript("length")//取出来的JSValue遵循JavaScript中的数组属性,所以可以直接取到JavaScript数组中的“length”取得数组中的长度
 8         println("ocnames:\(ocnames) count: \(len.toInt32())")//ocnames:Grace,Joe,Mike count: 3 JSValue转化为swift中的Int:len.toInt32()
 9         ocnames.setObject("himily", atIndexedSubscript: 8)
10         len = ocnames.objectForKeyedSubscript("length")
11         println("after set ‘himily‘ at indext 8 ocnames:\(ocnames) count: \(len.toInt32())")//after set ‘himily‘ at indext 8 ocnames:Grace,Joe,Mike,,,,,,himily count: 9 取出来的JSValue遵循JavaScript中的数组属性,无下标越界,自动延展数组大小
12         let firstName:JSValue = ocnames.objectAtIndexedSubscript(1)//取出JS运行环境里的数组中指定下标的元素
13         println("first name = \(firstName)")//first name = Joe
14         let tripleFun:JSValue = context.objectForKeyedSubscript("triple")//取出JS运行环境中的方法
15         let tripleResult = tripleFun.callWithArguments([9])//调用JS运行环境 中的方法

代码注释已经很清楚,从上面代码我们总结几点:

1、在OC/swift里,所有JavaScript代码都需要在JavaScript运行环境(JSContext)中通过evaluateScript运行;

2、在OC/swift里,所有JavaScript中的方法、对象、属性都需要通过objectForKeyedSubscript来取得,取得所有对象均为JSValue类型

3、通过objectForKeyedSubscript取得的JavaScript中的对象,都遵循该对象在JavaScript中有的所有特性,如上述代码中数组的长度,无数组越界,自动延展的特性

4、通过objectForKeyedSubscript取得的JavaScript中的方法,均可以通过callWithArguments传入参数调用JavaScript中的方法并返回正确的结果(类型仍然为JSValue)

三、JacaScript环境中异常检测
1   //异常处理 用于检查和记录语法、类型和运行时的错误,该闭包可以检测当前context中所有JavaScript的出错
2         context.exceptionHandler = {context,exception in
3             println("JS Error:\(exception)")
4         }
5         context.evaluateScript("function sqare(value1,value2){return value1 * value2")//JS Error:SyntaxError: Unexpected end of script 检测到语法出错  没有右边的“}”
6          context.evaluateScript("function sqare(value1,value2){return value1 * value2}")

在OC中exceptionHandler是block 在swift中exceptionHandler是闭包,用于检测当然JSContext运行环境中所有JavaScript代码的语法错误。如上述例子抛出了语句没结束的异常;

四、JSExport

创建一个继承JSExport协议的PersonJSExports

1 @objc protocol PersonJSExports:JSExport{
2     var firstName:String{get set}
3     var lastName:String{get set}
4     var birthYear:NSNumber?{get set}
5 }

创建一个Person,让它继承PersonJSExports协议

 1 @objc class Person:NSObject,PersonJSExports{
 2     dynamic var firstName:String
 3     dynamic var lastName:String
 4     dynamic var birthYear:NSNumber?
 5     init(firstName:String,lastName:String){
 6         self.firstName = firstName
 7         self.lastName = lastName
 8         self.birthYear = NSNumber(int: 1986)
 9     }
10 }

创建一个Person的对象实例,记其成为contex环境中的“Person”

 1     var personal:Person = Person(firstName: "lily", lastName: "king")
 2         context.setObject(personal, forKeyedSubscript:"Person")//把Person类导出到JS中去
 3         var p:JSValue = context.objectForKeyedSubscript("Person")
 4         var first:JSValue = p.objectForKeyedSubscript("firstName")
 5         var last:JSValue = p.objectForKeyedSubscript("lastName")
 6         var year:JSValue = p.objectForKeyedSubscript("birthYear")
 7
 8         println("p.first:\(first) p.last:\(last) p.year:\(year)")//这里面有个incorporate一词值得推敲,经过验证只有直接继承了JSExport的中自定义协议(@protocol)(定义的属性、方法)才能在JSContext中访问到 分两种情况 1.如果PersonJSExports(直接继承JSExport)里有定义firstName、lastName则打印出 p.first:lily p.last:king 2、如果PersonJSExports里没有定义firstName、lastName则打印出p.first:undefined p.last:undefined
 9         personal.firstName = "lucy"
10         personal.lastName = "queen"
11         personal.birthYear = NSNumber(int: 1999)
12         var first1:JSValue = p.objectForKeyedSubscript("firstName")
13         var last1:JSValue = p.objectForKeyedSubscript("lastName")
14         var year1:JSValue = p.objectForKeyedSubscript("birthYear")
15         println("aftter change p.first:\(first1) p.last:\(last1) p.year:\(year1)")//经过验证只有直接继承了JSExport的中自定义协议(@protocol)(定义的属性、方法)才能在JSContext中访问到 分两种情况 1.如果PersonJSExports(直接继承JSExport)里有定义firstName、lastName则打印出 p.first:lucy p.last:queen 2、如果PersonJSExports里没有定义firstName、lastName则打印出aftter change p.first:undefined p.last:undefined full name undefined

由上面代码的输出可以看到,只有直接继承了JSExport的中自定义协议(@protocol)(定义的属性、方法)才能在JSContext中访问到。

关于JSExport中定义的方法,用OC来写一段

定义一个UIButtonJsexport让其直接继承JSExport协议

1 @protocol UIButtonJsexport <JSExport>
2
3 - (void)setTitle:(NSString *)title forState:(UIControlState)state;
4
5 @end

创建 一个button,同时把UIButton添加一个UIButtonJsexport协议class_addProtocol([UIButton class], @protocol(UIButtonJsexport));

 1  class_addProtocol([UIButton class], @protocol(UIButtonJsexport));
 2     UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 40)];
 3     [button setTitle:@"objective-c" forState:UIControlStateNormal];
 4     [button setBackgroundColor:[UIColor blueColor]];
 5     [self.view addSubview:button];
 6     context = [[JSContext alloc] init];
 7     [context setObject:button forKeyedSubscript:@"button"];
 8     context.exceptionHandler = ^(JSContext *con,JSValue *exception){
 9         con.exception = exception;
10         NSLog(@"JS error:%@",exception);
11     };
12     [button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];

点击的时候在context中改变button的title

1 -(void)click
2 {
3     [context evaluateScript:@"button.setTitleForState(‘JavaScript‘,0)"];
4 }

当运行点击UIButton时就会看到button的title被改变了,也证明了对于已定义的类,也可以在运行时添加神奇的JSExport协议让它们可以在Objective-C和JavaScript直接实现友好互通。

时间: 2024-10-27 06:49:59

JavaScriptCore in swift的相关文章

iOS8开发~Swift(一)入门

一.概论及Swift介绍 iOS7刚公布多时候,苹果引入了JavaScriptCore.framework用来处理JavaScript,看到了能够接触其它编程语言的契机,使iOS程序猿不用吊死在OC这一颗树上.当但iOS8公布的时候.简直Hold不住了.新的开发语言<Swift>出现了!Swift是一种新的编程语言,基于C和OC.可用于Cocoa和Cocoa Touch编程.编写代码中充满互动性和乐趣,且语法简洁而传神,能够使应用程序执行飞快.Swift是以后iOS和OS X的项目开发语言的选

UIWebView开发中,js与oc,js与swift交互,相互传递参数的方法

实际开发中经常遇到需要向webView传递参数或从webView取参数,在此写了个超简单的demo供大家参考,本人js刚学了一天,所以不足之处海涵. 废话不多说,直接上代码 oc版 1 #import "ViewController.h" 2 @interface ViewController ()<UIWebViewDelegate> 3 @property (nonatomic, strong)UIWebView * webView; 4 @end 5 6 @imple

在 Swift 專案中使用 Javascript:編寫一個將 Markdown 轉為 HTML 的編輯器

原文:Using JavaScript in Swift Projects: Building a Markdown to HTML Editor 作者:GABRIEL THEODOROPOULOS 譯者:kmyhy 一直想寫一篇文章,關於如何將 Swift 和 Javascript 結合在一起,以構建強大的支持富文本的 App.這並不是我們第一次聽人說要將 Javacript 代碼嵌入到 iOS 專案中了,但當你讀完本文后,你會感到這個過程會變得前所未有的簡單,仿佛魔術一般,你只需要做很少的工

JavaScriptCore学习之JavaScriptCore

JavaScriptCore框架的类 JavaScriptCore框架对外暴露的类实际上非常少,这样带来的好处是API非常简单.如下图所示,只有5个类,分别是JSContext,JSValue,JSManagedValue,JSVirtualMachine,JSExport,其中最核心的是JSContext和JSValue,我们平时打交道的基本就是这两个类了. 这些类的基本介绍如下: JSVirtualMachine A JSVirtualMachine instance represents

OC与JS交互之JavaScriptCore

本文摘抄自:https://hjgitbook.gitbooks.io/ios/content/04-technical-research/04-javascriptcore-note.html JavaScriptCore初探 注:JavaScriptCore API也可以用Swift来调用,本文用Objective-C来介绍. 在iOS7之前,原生应用和Web应用之间很难通信.如果你想在iOS设备上渲染HTML或者运行JavaScript,你不得不使用UIWebView.iOS7引入了Jav

iOS插件化研究之一——JavaScriptCore

原文:http://chentoo.com/?p=191 一.前言 一样的开篇问题,为什么要研究这个?iOS为什么要插件化?为什么要借助其他语言比如html5 js甚至脚本lua等来实现原本OC/Swift应该实现的东西? 原因可以归结为两点: 1. iOS平台 appstore 审核速度不可控,而很多活动页面需要频繁更新,如果每次更新都走appstore审核流程,那活动也就不要做了. 2. 可多平台复用代码,节省开发成本.比如同一个活动的页面,用html5+js完成,就可以通用的在iOS An

Apple Swift编程语言新手教程

Apple Swift编程语言新手教程 作者: 日期: gashero 2014-06-03 FROM:http://gashero.iteye.com/blog/2075324 文件夹 1   简单介绍 2   Swift入门 3   简单值 4   控制流 5   函数与闭包 6   对象与类 7   枚举与结构 1   简单介绍 今天凌晨Apple刚刚公布了Swift编程语言,本文从其公布的书籍<The Swift Programming Language>中摘录和提取而成.希望对各位的

swift 深入理解Swift的闭包

我们可用swift的闭包来定义变量的值. 先来一个简单的例子大家先感受感受. 定义一个字符串的变量的方法: 直接赋值 var str="JobDeer" 还可以用闭包的方式定义: var str:String={ return "JobDeer" }() 闭包还可以这么定义,省略了等号和括号: var str:String{ return "JobDeer" } 闭包中可以定义get方法. var str:String{ get{ return

在Swift结构体中如何实现写时复制?

结构体(Struct)在Swift语言中占有重要地位,在Swift标准库中,大约有90%的公开类型都是结构体,包括我们常用的Array.String.Dictionary.结构体相比类,一个最重要的特性就是它是值类型,而类似引用类型.值类型是通过复制值来赋值的,而不是引用同一个内存地址,这样就不存在数据共享的问题,能防止意外的数据改变,并且它是线程安全的. 举一个很简单的例子,在objc中,数组是类,是引用类型,在Swift中,数组是结构体,是值类型.因此下面的代码中: let array1 =