- 蘋果在 iOS7中增加了 JavaScriptCore 框架,而這個(gè)框架正是大大的簡(jiǎn)化 JavaScript 與 Objective-C之間的交互韧掩!它把 WebKit 的 JavaScript 引擎用 Objective-C 封裝,我們可以用很簡(jiǎn)便的方法快速的接入當(dāng)下流行的 JavaScript蔫饰。
- JavaScriptCore可以讓我們?cè)?OC 執(zhí)行的代碼的任何地方運(yùn)行JS 代碼,不依賴 WebView
- JavaScriptCore主要就是給我們提供了 JS 代碼的執(zhí)行環(huán)境并進(jìn)行解析運(yùn)行
- 讓我們應(yīng)用擴(kuò)展性大大提高愉豺,提供了動(dòng)態(tài)去修改我們局部代碼或者邏輯的思路(實(shí)現(xiàn)熱更新)篓吁,同時(shí)讓我們?nèi)デ度刖W(wǎng)頁(yè)并加以調(diào)整變得輕松。
簡(jiǎn)單的總結(jié)一下關(guān)于這個(gè)框架基礎(chǔ)使用蚪拦,才淺學(xué)薄欠缺之處望包含指正杖剪!
- JSContext
它是 JavaScript 代碼的運(yùn)行環(huán)境,也就是作用的范圍驰贷。每一個(gè) JSContext 就是一個(gè)全局的環(huán)境變量盛嘿!我們創(chuàng)建一個(gè) JSContext 對(duì)象之后,可以利用它去執(zhí)行相應(yīng)的JavaScript 的代碼操作(創(chuàng)建變量括袒,定義方法等)次兆!
- JSValue
它是為了處理 Objective-C 對(duì)象(強(qiáng)類型)和 JavaScript 對(duì)象(弱類型)差異的類,實(shí)現(xiàn) OC 和 JS 對(duì)象的相互轉(zhuǎn)化锹锰。在處理的時(shí)候 JSValue對(duì)象包裹著來(lái)自 JSContext 的值例如字符串芥炭、對(duì)象甚至是方法、還有一些錯(cuò)誤的特殊的 JS 值類似 null 和 undefined恃慧。這個(gè)類的一些列方法(得到 Foundation 框架下得類型)就是為了我們?cè)?OC 訪問這些值時(shí)候能夠正常的去訪問處理园蝠!可以理解成是 JS 和 OC 之間互相轉(zhuǎn)換的橋梁,下圖是一個(gè)簡(jiǎn)單總結(jié)的表格痢士!
JS類型 | JSValue轉(zhuǎn)OC | Swift 類型 | OC 類型 | OC 轉(zhuǎn) JSValue |
---|---|---|---|---|
string | toString | String! | NSString | |
boolean | toBool | Bool | Bool | valueWithBool:inContext: |
number | toNumberto toDouble toInt32 toUInt32 |
NSNumber! Double Int32 UInt32 |
NSNumber double int32_tuint32_t |
valueWithDouble:inContext: valueWithInt32:inContext: valueWithUInt32:inContext: |
Date | toDate | NSDate! | NSDate | |
Arrar | toArray | [AnyObject]! | NSArray | valueWithNewArrayInContext: |
Object | toDictionary | [NSObject : AnyObject]! | NSDictionary | valueWithNewObjectInContext: |
Object | toObject toObjectOfClass: |
custom type | custom type( id類型) | valueWithObject:inContext: |
undefined | nil | nil | valueWithUndefinedInContext | |
null | NSNull | NSNull | valueWithNullInContext: |
- 我們通過代碼簡(jiǎn)單理解一下 OC 和 JS交互簡(jiǎn)單實(shí)現(xiàn)
- 創(chuàng)建JSContext 對(duì)象
JSContext *context = [[JSContext alloc] init];```
- 用這個(gè)對(duì)象執(zhí)行 JS 代碼得到一個(gè) JSValue 對(duì)象
```code
JSValue *jsValue = [context evaluateScript:@"23+6"];```
- JSValue 值 轉(zhuǎn)換成 OC 的結(jié)果值
```code
int ocValue = [jsVlaue toInt32];```
- 執(zhí)行JS函數(shù)(OC中的 Block)這樣就相當(dāng)于下 JS 中調(diào)用了 OC 代碼
```code
// 就是把這個(gè)方法賦給 JS 的 log 這個(gè)屬性(沒有的話JS 會(huì)自動(dòng)創(chuàng)建這個(gè)屬性)
context[@"log"] = ^(NSInteger value){
NSLog(@"-------->%ld",value);// 這里打印了摻入的第一個(gè)傳入的參數(shù)
// 處理傳進(jìn)來(lái)的參數(shù)
NSArray *arr = [JSContext currentArguments]; // 返回一個(gè)數(shù)組 獲取到的是 JS 傳進(jìn)去的不定參數(shù)
for (id item in arr) {
NSLog(@"--->%@",item);// 依次打印了傳進(jìn)來(lái)的參數(shù)
}
};
// 執(zhí)行 JS 代碼
[context evaluateScript:@"log(11,2,3)"];```

- 我們也可以在 OC 中使用 JS 代碼結(jié)果
- 小例子:這里我寫一個(gè)求 1->n 和 以及 N 階乘 的 JS 代碼然后執(zhí)行結(jié)果轉(zhuǎn)成 OC 的
```code
JSContext *context = [[JSContext alloc] init];
# 這里是 JS 求和以及計(jì)算階乘的代碼
[context evaluateScript:@"var numSum = function(n){var sum = 0; for( i = 0;i <= n;i++ ){ sum += i; } return sum };var factorial = function(n) { if (n < 0) return; if (n === 0) return 1; return n * factorial(n - 1) };"];
JSValue *function = context[@"numSum"];
# 調(diào)用 JS 函數(shù)方法彪薛,并返回函數(shù)的結(jié)果 傳入的參數(shù)是一個(gè)給函數(shù)的傳遞的參數(shù)放到數(shù)組里面
JSValue *numSum = [function callWithArguments:@[@5]];
NSLog(@"把 JS結(jié)果轉(zhuǎn)化成 OC結(jié)果---->%d",[numSum toInt32]);```

--------
-----
- 再寫一個(gè)簡(jiǎn)單的例子,我們?cè)诶?OC 的WebView 加載 一個(gè)網(wǎng)頁(yè)怠蹂,網(wǎng)頁(yè)上有一個(gè) Button善延,點(diǎn)擊這個(gè) Button 我們 iOS 客戶端相應(yīng)的進(jìn)行一些操作也就是 OC 和 HTML 交互!
- 一個(gè)簡(jiǎn)單的 HTML 代碼
```code
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input type="button" value="login" onclick="log()" />
</body>
</html>
- 我們用 WebView 加載這個(gè) HTML
UIWebView *webview = [[UIWebView alloc] initWithFrame:CGRectMake(10, 10, 300, 500)];// 創(chuàng)建
[self.view addSubview:webview];// 添加父視圖
webview.delegate = self;// 設(shè)置代理
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];// 找到要加載的 HTML 文件
NSString *urlStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[webview loadHTMLString:urlStr baseURL:nil];// 加載```
- 我們?cè)诖矸椒ㄖ蝎@取這次加載
```code
// 每次加載網(wǎng)頁(yè)請(qǐng)求都會(huì)走該方法
- (void)webViewDidFinishLoad:(UIWebView *)webView
{// 獲取當(dāng)期WebView 相關(guān)的 context城侧,獲取 JS執(zhí)行環(huán)境
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// 我們把點(diǎn)擊的事件獲取到 也就實(shí)現(xiàn)了效果
context[@"log"] = ^(){
NSLog(@"點(diǎn)擊了網(wǎng)頁(yè)上那個(gè)的 Button挚冤!")
}```

- JSExport
> 要想在 JS 中調(diào)用OC 對(duì)象的方法和屬性,需要把這些屬性方法放到繼承于 JSExport 的協(xié)議中赞庶,因?yàn)橹挥蠮SExport 協(xié)議中的方法才能被 JavaScript 識(shí)別!OC 對(duì)象相應(yīng)的實(shí)現(xiàn)協(xié)議方法澳骤!
- 代碼示例我們先定義一個(gè)協(xié)議
```code
// 一定要繼承于 JSExport
@protocol JS_OC_Delegate <JSExport>
@property (nonatomic, strong) NSString *name;
@end```
- 在一個(gè)類中(這里是在 ViewController)中遵循代理并實(shí)現(xiàn)方法
```code
@synthesize name;```
- 轉(zhuǎn)化執(zhí)行
```code
self.name = @"云之君兮鵬";
JSContext *context = [[JSContext alloc] init];
context[@"OC_Object"] = self;
[context evaluateScript:@"OC_Object.name = '小超人'"];
NSLog(@"%s--->%@",__func__,self.name);
打印結(jié)果
注意一些問題:
不要在Block 中直接引用使用外面的
JSContext
對(duì)象歧强,應(yīng)該用·[JSContext currentContext];
同樣的不要直接在 Block 中調(diào)用外界的 JSValue 對(duì)象,需要的話可以利用參數(shù)傳遞進(jìn)去为肮。
- 原因(我們?cè)?OC 中經(jīng)程幔回去注意的問題,避免了循環(huán)引用颊艳,相互持有茅特!Block 可以保有變量引用忘分,而且 JSContext 也強(qiáng)引用它所有的變量。)當(dāng)我們使用JS 調(diào)用 OC 的回調(diào)方法時(shí)白修,均是在子線程中執(zhí)行的妒峦,這樣的話我們得注意需要的時(shí)候,要回到主線程去更新我們 UI 界面兵睛。
JSContext *context = [[JSContext alloc] init];
context[@"函數(shù)名"] = ^(類型 參數(shù)){
# 尷尬了 循環(huán)引用
JSValue *value = [JSValue valueWithNewObjectInContext:context];
# 顧德樂 正常使用
JSValue *value = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
};
今天先到這了肯骇,日后補(bǔ)充更新,開心就好!對(duì)了簡(jiǎn)友們節(jié)日快樂!