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個:
#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
//使用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端進行錯誤處理
context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
NSLog(@"JS Error: %@", exception);
};
3. 內存管理
Objective-C的內存管理機制是引用計數,JavaScript的內存管理機制是垃圾回收。在大部分情況下,JavaScriptCore能做到在這兩種內存管理機制之間無縫無錯轉換,但也有少數情況需要使用到JSManagedValue對象解決,后面會給出對應鏈接。
三、使用JavaScriptCore重寫
沿用之前的示例,其他地方均無改動,只修改了兩邊交互的相關代碼:
OC端:
1. 初始化JScontext
self.jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
2. 注入JS代碼
__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端代碼
//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端:
//提供給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
