天天看點

ios webview html互動 卡死,iOS 之webview 的js互動(alert、confirm、prompt)彈窗造成界面卡死...

概述:當iOS用戶端中webView 與js互動,在主線程執行js腳本時,而js腳本存在alert()、confirm()、prompt()這三種彈窗時會造成iOS界面卡死。

1、造成卡死時的代碼如下:

NSString *script = "doSubmit()";

(1)

iOS端實作:

[self.webView stringByEvaluatingJavaScriptFromString:script];

js實作:

doSubmit = function (obj) {

if (confirm("已存在故障回報,确認繼續送出?")){

flag = true;

} else {

flag = false;

}

return flag;

}

(2)

iOS端實作:

dispatch_async(dispatch_get_main_queue(), ^{

[self.webView stringByEvaluatingJavaScriptFromString:script];

});

js實作:

doSubmit = function (obj) {

if (confirm("已存在故障回報,确認繼續送出?")){

flag = true;

} else {

flag = false;

}

return flag;

}

(3)

iOS端實作:

[self.webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:script waitUntilDone:YES];

js實作:

doSubmit = function (obj) {

if (confirm("已存在故障回報,确認繼續送出?")){

flag = true;

} else {

flag = false;

}

return flag;

}

2、卡死原因分析:

(1)第一種情況由于iOS端的js腳本是在主線程執行,而js的三種彈窗上的按鈕操作也必須在主線程完成,alert()、confirm()、prompt()這三種彈窗會中斷js腳本的執行,也就是彈窗上面的按鈕沒有點選響應結果前,if (confirm("已存在故障回報,确認繼續送出?"))後面的代碼将不會執行,此時 [self.webView stringByEvaluatingJavaScriptFromString:script];占用着主線程一直在等待return flag;語句執行完成。這将造成:點選彈窗的按鈕在等js執行return 語句拿到主線程重新整理UI,而占用主線程的一直在等js腳本執行完成的互相等待。

(2)第二種dispatch_async()造成卡死的原因如下:

ios webview html互動 卡死,iOS 之webview 的js互動(alert、confirm、prompt)彈窗造成界面卡死...

dispatch_async的實作代碼.jpg

上圖是dispatch_async()的實作代碼

dispatch_atomic_inc和dispatch_atomic_dec是原子操作函數;

由上圖可知dispatch_async執行任務的時候會對目前工作的線程加原子操作,而原子操作是不會被線程排程機制打斷的操作;這種操作一旦開始,就一直運作到結束,中間不會有任何 的線程切換, 任務不執行完, 工作線程是不會被中斷的。是以主線程執行的js腳本不會被中斷。

js中彈窗中斷代碼的作用, 彈窗下面的代碼在彈窗上面的按鈕點選之前是不會被執行到的。是以它們進入了互相等待資源中。

(3)

performSelectorOnMainThread: withObject: waitUntilDone:

這個方法中waitUntilDone:的參數官方注釋wait的意思:

A Boolean that specifies whether the current thread blocks until after the specified selector is performed on the receiver on the main thread.

Specify YES to block this thread;

otherwise, specify NO to have this method return immediately.

如果wait是YES,會鎖死主線程,直到selector方法執行完. 如果為NO,selector方法會立即傳回。

而iOS 用戶端實作的代碼是YES,是以存在競争主線程,造成界面卡死的問題。

3、卡死問題處理:

或:iOS端代碼實作修改:

[self.webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:script waitUntilDone:NO];

或:js代碼實作修改:

doSubmit = function (obj) {

setTimeout(function() {

if (confirm("已存在故障回報,确認繼續送出?")){

flag = true;

} else {

flag = false;

}

return flag;

},-1);

}

以上隻要有一端做修改即可。