iOS7新JavaScriptCore框架介紹

這個(gè)框架其實(shí)只是基于webkit中以C/C++實(shí)現(xiàn)的JavaScriptCore的一個(gè)包裝容诬,在舊版本iOS開發(fā)中,很多開發(fā)者也會(huì)自行將webkit的庫引入項(xiàng)目編譯使用秩彤。不過雖然iOS7把它當(dāng)成了標(biāo)準(zhǔn)庫叔扼,可惜目前事哭,我還沒有在Apple Developer中找到像那樣的官方文檔介紹這個(gè)框架的具體使用方法。

JavaScriptCore中的類
在項(xiàng)目中引入JavaScriptCore后瓜富,鏈到頭文件中鳍咱,除了大段的Copyright注釋可以看到里面只要引入了5個(gè)文件,每個(gè)文件里都定義跟文件名對(duì)應(yīng)的類:

  1. JSContext
  2. JSValue
  3. JSManagedValue
  4. JSVirtualMachine
  5. JSExport


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

JSContext和JSValue
JSVirtualMachine為JavaScript的運(yùn)行提供了底層資源丑念,JSContext就為其提供著運(yùn)行環(huán)境,通過- (JSValue *)evaluateScript:(NSString *)script;方法就可以執(zhí)行一段JavaScript腳本结蟋,并且如果其中有方法脯倚、變量等信息都會(huì)被存儲(chǔ)在其中以便在需要的時(shí)候使用。而JSContext的創(chuàng)建都是基于JSVirtualMachine:- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;嵌屎,如果是使用- (id)init;進(jìn)行初始化挠将,那么在其內(nèi)部會(huì)自動(dòng)創(chuàng)建一個(gè)新的JSVirtualMachine對(duì)象然后調(diào)用前邊的初始化方法。

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


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

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

很簡(jiǎn)單吧掌测,還可以存一個(gè)JavaScript變量在JSContext中,然后通過下標(biāo)來獲取出來产园。而對(duì)于Array或者Object類型汞斧,JSValue也可以通過下標(biāo)直接取值和賦值。

 JSContext *context = [[JSContext alloc] init]; 
 [context evaluateScript:@"var arr = [21, 7 , 'iderzheng.com'];"]; 
 JSValue *jsArr = context[@"arr"]; // Get array from JSContext 
       
 NSLog(@"JS Array: %@; Length: %@", jsArr, jsArr[@"length"]); 
 jsArr[1] = @"blog"; // Use JSValue as array 
 jsArr[7] = @7; 
   
 NSLog(@"JS Array: %@; Length: %d", jsArr, [jsArr[@"length"] toInt32]); 
      
 NSArray *nsArr = [jsArr toArray]; 
 NSLog(@"NSArray: %@", nsArr); 
    
 //Output: 
 // JS Array: 21,7,iderzheng.com Length: 3 
 // JS Array: 21,blog,iderzheng.com,,,,,7 Length: 8 
 // NSArray: ( 
 // 21, 
 // blog, 
 // "iderzheng.com", 
 // "",
 
 // "",
 
 // "",
 
 // "",
 
 // 7 
 // ) 

通過輸出結(jié)果很容易看出代碼成功把數(shù)據(jù)從Objective-C賦到了JavaScript數(shù)組上什燕,而且JSValue是遵循JavaScript的數(shù)組特性:無下標(biāo)越位粘勒,自動(dòng)延展數(shù)組大小。并且通過JSValue還可以獲取JavaScript對(duì)象上的屬性屎即,比如例子中通過"length"就獲取到了JavaScript數(shù)組的長(zhǎng)度庙睡。在轉(zhuǎn)成NSArray的時(shí)候,所有的信息也都正確轉(zhuǎn)換了過去技俐。

方法的轉(zhuǎn)換
各種數(shù)據(jù)類型可以轉(zhuǎn)換乘陪,Objective-C的Block也可以傳入JSContext中當(dāng)做JavaScript的方法使用。比如在前端開發(fā)中常用的log方法雕擂,雖然JavaScritpCore沒有自帶(畢竟不是在網(wǎng)頁上運(yùn)行的啡邑,自然不會(huì)有window、document井赌、console這些類了)谤逼,仍然可以定義一個(gè)Block方法來調(diào)用NSLog來模擬:

JSContext *context = [[JSContext alloc] init]; 
context[@"log"] = ^() { 
 NSLog(@"+++++++Begin Log+++++++");   
 NSArray *args = [JSContext currentArguments]; 
for (JSValue *jsVal in args) { 
 NSLog(@"%@", jsVal); 
 }   
  
JSValue *this = [JSContext currentThis]; 
NSLog(@"this: %@",this); 
NSLog(@"-------End Log-------"); 
}; 
      
[context evaluateScript:@"log('ider', [7, 21], { hello:'world', js:100 });"]; 
      
  //Output: 
  // +++++++Begin Log+++++++ 
  // ider 
  // 7,21 
  // [object Object] 
  // this: [object GlobalObject] 
  // -------End Log------- 

通過Block成功的在JavaScript調(diào)用方法回到了Objective-C贵扰,而且依然遵循JavaScript方法的各種特點(diǎn),比如方法參數(shù)不固定流部。也因?yàn)檫@樣戚绕,JSContext提供了類方法來獲取參數(shù)列表(+ (JSContext *)currentContext;)和當(dāng)前調(diào)用該方法的對(duì)象(+ (JSValue *)currentThis)。對(duì)于"this"贵涵,輸出的內(nèi)容是GlobalObject列肢,這也是JSContext對(duì)象方法- (JSValue *)globalObject;所返回的內(nèi)容。因?yàn)槲覀冎涝贘avaScript里宾茂,所有全局變量和方法其實(shí)都是一個(gè)全局變量的屬性瓷马,在瀏覽器中是window,在JavaScriptCore是什么就不得而知了跨晴。

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


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

JSValue還提供- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;讓我們可以直接簡(jiǎn)單地調(diào)用對(duì)象上的方法焕妙。只是如果定義的方法是全局函數(shù)蒋伦,那么很顯然應(yīng)該在JSContext的globalObject對(duì)象上調(diào)用該方法;如果是某JavaScript對(duì)象上的方法焚鹊,就應(yīng)該用相應(yīng)的JSValue對(duì)象調(diào)用痕届。

異常處理
Objective-C的異常會(huì)在運(yùn)行時(shí)被Xcode捕獲,而在JSContext中執(zhí)行的JavaScript如果出現(xiàn)異常末患,只會(huì)被JSContext捕獲并存儲(chǔ)在exception屬性上研叫,而不會(huì)向外拋出。時(shí)時(shí)刻刻檢查JSContext對(duì)象的exception是否不為nil顯然是不合適璧针,更合理的方式是給JSContext對(duì)象設(shè)置exceptionHandler嚷炉,它接受的是^(JSContext *context, JSValue *exceptionValue)形式的Block。其默認(rèn)值就是將傳入的exceptionValue賦給傳入的context的exception屬性:

(JSContext *context, JSValue *exceptionValue) { 
         context.exception = exceptionValue; 
     }; 

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

JSContext *context = [[JSContext alloc] init]; 
context.exceptionHandler = ^(JSContext *con, JSValue *exception) { 
NSLog(@"%@", exception); 
con.exception = exception; 
}; 
 
[context evaluateScript:@"ider.zheng = 21"]; 
      
//Output: 
// ReferenceError: Can't find variable: ider 

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

比如上邊自定義異常處理方法,就是賦給傳入JSContext對(duì)象con索绪,而不是其外創(chuàng)建的context對(duì)象湖员,雖然它們其實(shí)是同一個(gè)對(duì)象。這是因?yàn)锽lock會(huì)對(duì)內(nèi)部使用的在外部定義創(chuàng)建的對(duì)象做強(qiáng)引用瑞驱,而JSContext也會(huì)對(duì)被賦予的Block做強(qiáng)引用娘摔,這樣它們之間就形成了循環(huán)引用(Circular Reference)使得內(nèi)存無法正常釋放。
對(duì)于JSValue也不能直接從外部引用到Block中唤反,因?yàn)槊總€(gè)JSValue上都有JSContext的引用 (@property(readonly, retain) JSContext *context;)凳寺,JSContext再引用Block同樣也會(huì)形成引用循環(huán)。

轉(zhuǎn)自:http://blog.csdn.net/kaitiren/article/details/23255707

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末彤侍,一起剝皮案震驚了整個(gè)濱河市肠缨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盏阶,老刑警劉巖晒奕,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異名斟,居然都是意外死亡脑慧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門砰盐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闷袒,“玉大人,你說我怎么就攤上這事岩梳∧抑瑁” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蒋腮,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我藕各,道長(zhǎng)池摧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任激况,我火速辦了婚禮作彤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乌逐。我一直安慰自己竭讳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布浙踢。 她就那樣靜靜地躺著绢慢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洛波。 梳的紋絲不亂的頭發(fā)上胰舆,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天骚露,我揣著相機(jī)與錄音,去河邊找鬼缚窿。 笑死棘幸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倦零。 我是一名探鬼主播误续,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼扫茅!你這毒婦竟也來了蹋嵌?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤诞帐,失蹤者是張志新(化名)和其女友劉穎欣尼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體停蕉,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡愕鼓,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慧起。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菇晃。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蚓挤,靈堂內(nèi)的尸體忽然破棺而出磺送,到底是詐尸還是另有隱情,我是刑警寧澤灿意,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布估灿,位于F島的核電站,受9級(jí)特大地震影響缤剧,放射性物質(zhì)發(fā)生泄漏馅袁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一荒辕、第九天 我趴在偏房一處隱蔽的房頂上張望汗销。 院中可真熱鬧,春花似錦抵窒、人聲如沸弛针。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽削茁。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間付材,已是汗流浹背朦拖。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厌衔,地道東北人璧帝。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像富寿,于是被迫代替她去往敵國(guó)和親睬隶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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