2016年12月03日星期六
- 今天在使用JavaScriptCore和UIWebView交互使用的時(shí)候,出現(xiàn)了非常奇怪的問題逊笆。
問題如下面所敘:- 我在JS->OC->JS的最后一步:OC->JS的時(shí)候栈戳,出現(xiàn)了問題。之前我沒有調(diào)用alert()方法难裆,用js作個(gè)彈出框來顯示JS傳給OC后子檀,OC操作后的數(shù)據(jù)通過,OC->JS來完成在js中以彈出框來顯示乃戈。
代碼順序如下:
- 我在JS->OC->JS的最后一步:OC->JS的時(shí)候栈戳,出現(xiàn)了問題。之前我沒有調(diào)用alert()方法难裆,用js作個(gè)彈出框來顯示JS傳給OC后子檀,OC操作后的數(shù)據(jù)通過,OC->JS來完成在js中以彈出框來顯示乃戈。
- js
function showSelect(){
var selectParams = {
title : "提示標(biāo)題",//提示標(biāo)題
list : new Array("選項(xiàng)一","選項(xiàng)二","6666","哈哈哈"),//選擇列表
buttonA : "確定",
buttonB : "取消",
buttonOnclick : function(data){
//列表選擇結(jié)果
alert(data);
document.getElementById("result").innerText = data;
}};
ddd.webview.showListSelect(selectParams);
- OC
dispatch_async(dispatch_get_main_queue(), ^{
JSValue *yx = self.jsContext[@"ddd"];
JSValue *webview = yx[@"webview"];
JSValue *commonButtonOnClickLinstener = webview[@"commonButtonOnClickListener"];
[commonButtonOnClickLinstener[@"buttonOnclick"] callWithArguments:@[@"ddd"]];
});
在OC中回調(diào)的時(shí)候褂痰,沒有在主線程操作的話,整個(gè)UI界面會停留在症虑,JS彈出框出來之前的界面缩歪,界面平靜的沒有一絲波紋。
在使用了主線程之后谍憔,UI界面就跟一個(gè)癩蛤蟆一樣匪蝙,你碰一下就動(dòng)一下。UI界面停止在JS彈出框出來的界面(喲呵)习贫。
查看了一下逛球,百度,呵呵噠苫昌,除了簡單的介紹如何讓你javascriptcore入門颤绕,講解的稍微深點(diǎn)的,都是非常少祟身。
在stack overflow上找了半天 終于尋到了一絲頭緒奥务。是線程的問題,不知道是阻塞了主線程還是子線程被阻塞了袜硫,反正在你回調(diào)js的那一刻氯葬,就是有問題。具體是什么問題父款,我也不好揣測溢谤,畢竟才疏學(xué)淺瞻凤。
但是經(jīng)過檢測,把解決方案試了出來世杀。
-(void)DelegateFunc:(NSString *)str{//某個(gè)代理回調(diào)函數(shù)(模擬一下)
[self performSelectorOnMainThread:@selector(ddd) withObject:nil waitUntilDone:NO];
}
-(void)ddd{
JSValue *yx = self.jsContext[@"ddd"];
JSValue *webview = yx[@"webview"];
JSValue *commonButtonOnClickLinstener = webview[@"commonButtonOnClickListener"];
[commonButtonOnClickLinstener[@"buttonOnclick"] callWithArguments:@[@"ddd"]];
}
- 這樣執(zhí)行下來就算是讓他們繼續(xù)工作了阀参。
當(dāng)然這里貼一下 [self performSelectorOnMainThread:@selector(ddd) withObject:nil waitUntilDone:NO] 中waitUntilDone參數(shù)設(shè)定的功效:- YES: 等ddd()方法執(zhí)行完成后,子線程才會繼續(xù)執(zhí)行后面的代碼瞻坝。
- NO: 不用等待等待ddd()方法執(zhí)行完成后蛛壳,直接執(zhí)行后面的代碼。
(2017-4-13日補(bǔ)充:這個(gè)的意思是把任務(wù)放在主線程上執(zhí)行所刀。錯(cuò)啦?)
2018-3-06日補(bǔ)充:回到webView的線程去調(diào)用
(callWithArguments就不會崩潰(因?yàn)閖s和oc綁定的函數(shù)衙荐,在函數(shù)里執(zhí)行的代碼不是在主線程里執(zhí)行的)。
模擬代碼:
///假設(shè)這個(gè)函數(shù)是和js的test函數(shù)綁定的浮创。如果監(jiān)聽到這個(gè)函數(shù)就進(jìn)行網(wǎng)絡(luò)請求或者上傳圖片等操作忧吟。
- (void)test {
//獲取webView線程,因?yàn)閖s和oc綁定的函數(shù)里執(zhí)行的代碼不是在主線程里斩披。
NSThread *webThread = [NSThread currentThread];
//網(wǎng)絡(luò)請求
@weakify(self);
[HTTPRequest requestGetTokenWithFinished:^(void){
@strongify(self);
//通知js請求完了溜族。
//正常情況下是直接在這里調(diào)用,但是會間接性發(fā)生野指針問題垦沉,差不多每隔四五次發(fā)生一次野指針煌抒。
//JSValue *jsCall = self.context[@"jsCall"];
//[jsCall callWithArguments:nil];
//線程安全的,用此方式厕倍,筆者再也沒發(fā)生過野指針問題寡壮。
[self performSelector:@selector(jsCall) onThread:webThread withObject:nil waitUntilDone:NO];
}];
}
- (void)jsCall {
JSValue *jsCall = self.context[@"jsCall"];
[jsCall callWithArguments:nil];
})