iOS7新JavaScriptCore框架介紹

這個框架其實只是基于webkit中以C/C++實現(xiàn)的JavaScriptCore的一個包裝,在舊版本iOS開發(fā)中,很多開發(fā)者也會自行將webkit的庫引入項目編譯使用幻件。不過雖然iOS7把它當(dāng)成了標(biāo)準(zhǔn)庫卸例,可惜目前,我還沒有在Apple Developer中找到像那樣的官方文檔介紹這個框架的具體使用方法始苇。
JavaScriptCore中的類
在項目中引入JavaScriptCore后砌烁,鏈到頭文件中,除了大段的Copyright注釋可以看到里面只要引入了5個文件催式,每個文件里都定義跟文件名對應(yīng)的類:

JSContext
JSValue
JSManagedValue
JSVirtualMachine
JSExport

JavaScriptCore_Head.jpg

雖說代碼中的注釋介紹的也比較詳細(xì)了函喉,但是如同一圖頂萬言,對程序員來說代碼更有說服力荣月。本文就先來說說這些類相對比較好理解但又很常用的JSContext和JSValue以及它們方法的使用方式和效果管呵。

JSContext和JSValue
JSVirtualMachine為JavaScript的運行提供了底層資源,JSContext就為其提供著運行環(huán)境哺窄,通過- (JSValue *)evaluateScript:(NSString *)script;方法就可以執(zhí)行一段JavaScript腳本捐下,并且如果其中有方法账锹、變量等信息都會被存儲在其中以便在需要的時候使用。而JSContext的創(chuàng)建都是基于JSVirtualMachine:- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;坷襟,如果是使用- (id)init;進(jìn)行初始化奸柬,那么在其內(nèi)部會自動創(chuàng)建一個新的JSVirtualMachine對象然后調(diào)用前邊的初始化方法。

JSValue則可以說是JavaScript和Object-C之間互換的橋梁婴程,它提供了多種方法可以方便地把JavaScript數(shù)據(jù)類型轉(zhuǎn)換成Objective-C廓奕,或者是轉(zhuǎn)換過去。其一一對應(yīng)方式可見下表:

D7A59711-2166-460F-8D2A-CF3D009464B2.png

基本類型轉(zhuǎn)換
先看個簡單的例子:

1     JSContext *context = [[JSContext alloc] init];
2     JSValue *jsVal = [context evaluateScript:@"21+7"];
3     int iVal = [jsVal toInt32];
4     NSLog(@"JSValue: %@, int: %d", jsVal, iVal);
5      
6     //Output:
7     // JSValue: 28, int: 28

很簡單吧档叔,還可以存一個JavaScript變量在JSContext中懂从,然后通過下標(biāo)來獲取出來。而對于Array或者Object類型蹲蒲,JSValue也可以通過下標(biāo)直接取值和賦值番甩。

 1     JSContext *context = [[JSContext alloc] init];
 2     [context evaluateScript:@"var arr = [21, 7 , 'iderzheng.com'];"];
 3     JSValue *jsArr = context[@"arr"]; // Get array from JSContext
 4      
 5     NSLog(@"JS Array: %@; Length: %@", jsArr, jsArr[@"length"]);
 6     jsArr[1] = @"blog"; // Use JSValue as array
 7     jsArr[7] = @7;
 8      
 9     NSLog(@"JS Array: %@; Length: %d", jsArr, [jsArr[@"length"] toInt32]);
10      
11     NSArray *nsArr = [jsArr toArray];
12     NSLog(@"NSArray: %@", nsArr);
13      
14     //Output:
15     // JS Array: 21,7,iderzheng.com Length: 3
16     // JS Array: 21,blog,iderzheng.com,,,,,7 Length: 8
17     // NSArray: (
18     // 21,
19     // blog,
20     // "iderzheng.com",
21     // "<null>",
22     // "<null>",
23     // "<null>",
24     // "<null>",
25     // 7
26     // )

通過輸出結(jié)果很容易看出代碼成功把數(shù)據(jù)從Objective-C賦到了JavaScript數(shù)組上,而且JSValue是遵循JavaScript的數(shù)組特性:無下標(biāo)越位届搁,自動延展數(shù)組大小缘薛。并且通過JSValue還可以獲取JavaScript對象上的屬性,比如例子中通過"length"就獲取到了JavaScript數(shù)組的長度卡睦。在轉(zhuǎn)成NSArray的時候宴胧,所有的信息也都正確轉(zhuǎn)換了過去。

方法的轉(zhuǎn)換
各種數(shù)據(jù)類型可以轉(zhuǎn)換表锻,Objective-C的Block也可以傳入JSContext中當(dāng)做JavaScript的方法使用恕齐。比如在前端開發(fā)中常用的log方法,雖然JavaScritpCore沒有自帶(畢竟不是在網(wǎng)頁上運行的瞬逊,自然不會有window显歧、document、console這些類了)确镊,仍然可以定義一個Block方法來調(diào)用NSLog來模擬:

1     JSContext *context = [[JSContext alloc] init];
 2     context[@"log"] = ^() {
 3     NSLog(@"+++++++Begin Log+++++++");
 4      
 5     NSArray *args = [JSContext currentArguments];
 6     for (JSValue *jsVal in args) {
 7     NSLog(@"%@", jsVal);
 8     }
 9      
10     JSValue *this = [JSContext currentThis];
11     NSLog(@"this: %@",this);
12     NSLog(@"-------End Log-------");
13     };
14      
15     [context evaluateScript:@"log('ider', [7, 21], { hello:'world', js:100 });"];
16      
17     //Output:
18     // +++++++Begin Log+++++++
19     // ider
20     // 7,21
21     // [object Object]
22     // this: [object GlobalObject]
23     // -------End Log-------

通過Block成功的在JavaScript調(diào)用方法回到了Objective-C士骤,而且依然遵循JavaScript方法的各種特點,比如方法參數(shù)不固定蕾域。也因為這樣拷肌,JSContext提供了類方法來獲取參數(shù)列表(+ (JSContext *)currentContext;)和當(dāng)前調(diào)用該方法的對象(+ (JSValue *)currentThis)。對于"this"旨巷,輸出的內(nèi)容是GlobalObject巨缘,這也是JSContext對象方法- (JSValue *)globalObject;所返回的內(nèi)容。因為我們知道在JavaScript里采呐,所有全局變量和方法其實都是一個全局變量的屬性若锁,在瀏覽器中是window,在JavaScriptCore是什么就不得而知了懈万。

Block可以傳入JSContext作方法拴清,但是JSValue沒有toBlock方法來把JavaScript方法變成Block在Objetive-C中使用。畢竟Block的參數(shù)個數(shù)和類型已經(jīng)返回類型都是固定的会通。雖然不能把方法提取出來口予,但是JSValue提供了- (JSValue *)callWithArguments:(NSArray *)arguments;方法可以反過來將參數(shù)傳進(jìn)去來調(diào)用方法。

 1     JSContext *context = [[JSContext alloc] init];
 2     [context evaluateScript:@"function add(a, b) { return a + b; }"];
 3     JSValue *add = context[@"add"];
 4     NSLog(@"Func: %@", add);
 5      
 6     JSValue *sum = [add callWithArguments:@[@(7), @(21)]];
 7     NSLog(@"Sum: %d",[sum toInt32]);
 8     //OutPut:
 9     // Func: function add(a, b) { return a + b; }
10     // Sum: 28

JSValue還提供- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;讓我們可以直接簡單地調(diào)用對象上的方法涕侈。只是如果定義的方法是全局函數(shù)沪停,那么很顯然應(yīng)該在JSContext的globalObject對象上調(diào)用該方法;如果是某JavaScript對象上的方法裳涛,就應(yīng)該用相應(yīng)的JSValue對象調(diào)用木张。

異常處理
Objective-C的異常會在運行時被Xcode捕獲,而在JSContext中執(zhí)行的JavaScript如果出現(xiàn)異常端三,只會被JSContext捕獲并存儲在exception屬性上舷礼,而不會向外拋出。時時刻刻檢查JSContext對象的exception是否不為nil顯然是不合適郊闯,更合理的方式是給JSContext對象設(shè)置exceptionHandler妻献,它接受的是^(JSContext *context, JSValue *exceptionValue)形式的Block。其默認(rèn)值就是將傳入的exceptionValue賦給傳入的context的exception屬性:

1     ^(JSContext *context, JSValue *exceptionValue) {
2         context.exception = exceptionValue;
3     };

我們也可以給exceptionHandler賦予新的Block以便在JavaScript運行發(fā)生異常的時候我們可以立即知道:

1     JSContext *context = [[JSContext alloc] init];
 2     context.exceptionHandler = ^(JSContext *con, JSValue *exception) {
 3         NSLog(@"%@", exception);
 4         con.exception = exception;
 5     };
 6      
 7     [context evaluateScript:@"ider.zheng = 21"];
 8      
 9     //Output:
10     // ReferenceError: Can't find variable: ider

使用Block的注意事項
從之前的例子和介紹應(yīng)該有體會到Block在JavaScriptCore中起到的強大作用团赁,它在JavaScript和Objective-C之間的轉(zhuǎn)換 建立起更多的橋梁育拨,讓互通更方便。但是要注意的是無論是把Block傳給JSContext對象讓其變成JavaScript方法欢摄,還是把它賦給exceptionHandler屬性熬丧,在Block內(nèi)都不要直接使用其外部定義的JSContext對象或者JSValue,應(yīng)該將其當(dāng)做參數(shù)傳入到Block中怀挠,或者通過JSContext的類方法+ (JSContext *)currentContext;來獲得析蝴。否則會造成循環(huán)引用使得內(nèi)存無法被正確釋放。

比如上邊自定義異常處理方法绿淋,就是賦給傳入JSContext對象con嫌变,而不是其外創(chuàng)建的context對象,雖然它們其實是同一個對象躬它。這是因為Block會對內(nèi)部使用的在外部定義創(chuàng)建的對象做強引用腾啥,而JSContext也會對被賦予的Block做強引用,這樣它們之間就形成了循環(huán)引用(Circular Reference)使得內(nèi)存無法正常釋放冯吓。
對于JSValue也不能直接從外部引用到Block中倘待,因為每個JSValue上都有JSContext的引用 (@property(readonly, retain) JSContext *context;),JSContext再引用Block同樣也會形成引用循環(huán)组贺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凸舵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子失尖,更是在濱河造成了極大的恐慌啊奄,老刑警劉巖渐苏,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異菇夸,居然都是意外死亡琼富,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門庄新,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鞠眉,“玉大人,你說我怎么就攤上這事择诈⌒堤#” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵羞芍,是天一觀的道長哗戈。 經(jīng)常有香客問我,道長荷科,這世上最難降的妖魔是什么谱醇? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮步做,結(jié)果婚禮上副渴,老公的妹妹穿的比我還像新娘。我一直安慰自己全度,他們只是感情好煮剧,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著将鸵,像睡著了一般勉盅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上顶掉,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天草娜,我揣著相機與錄音,去河邊找鬼痒筒。 笑死宰闰,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的簿透。 我是一名探鬼主播移袍,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼老充!你這毒婦竟也來了葡盗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤啡浊,失蹤者是張志新(化名)和其女友劉穎觅够,沒想到半個月后胶背,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡喘先,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年钳吟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苹祟。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡砸抛,死狀恐怖评雌,靈堂內(nèi)的尸體忽然破棺而出树枫,到底是詐尸還是另有隱情,我是刑警寧澤景东,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布砂轻,位于F島的核電站,受9級特大地震影響斤吐,放射性物質(zhì)發(fā)生泄漏搔涝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一和措、第九天 我趴在偏房一處隱蔽的房頂上張望庄呈。 院中可真熱鬧,春花似錦派阱、人聲如沸诬留。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽文兑。三九已至,卻和暖如春腺劣,著一層夾襖步出監(jiān)牢的瞬間绿贞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工橘原, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留籍铁,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓趾断,卻偏偏與公主長得像寨辩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子歼冰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 這個框架其實只是基于webkit中以C/C++實現(xiàn)的JavaScriptCore的一個包裝靡狞,在舊版本iOS開發(fā)中,...
    _健健閱讀 638評論 0 51
  • 本文由我們團隊的 糾結(jié)倫 童鞋撰寫隔嫡。 寫在前面 本篇文章是對我一次組內(nèi)分享的整理甸怕,大部分圖片都是直接從keynot...
    知識小集閱讀 15,242評論 11 172
  • 原:https://github.com/YanlongMa/SwiftJavaScriptCore 注:Java...
    Tippi閱讀 371評論 0 1
  • 注:本文copy自http://www.reibang.com/p/ac534f508fb0甘穿,純屬當(dāng)筆記使用。 概...
    BookKeeping閱讀 731評論 1 3
  • 寫在前面 本篇文章是對我一次組內(nèi)分享的整理梢杭,大部分圖片都是直接從keynote上截圖下來的温兼,本來有很多炫酷動效的,...
    等開會閱讀 14,435評論 6 69