背景
項目中使用了wkwebview替換了之前的uiwebview,牽扯到hybird開發(fā),我們需要和h5交互,所以用到了wkwebviewconfiguration 中的 wkusercontentcontroller
所以初始化代碼如下
1
2
3
4
5
6
7
8
9
10
11
|
wkusercontentcontroller *usercontentcontroller = [[wkusercontentcontroller alloc] init]; [usercontentcontroller addscriptmessagehandler:self name:getkeyiosandroid_action]; [usercontentcontroller addscriptmessagehandler:self name:upload_action]; // wkwebview的配置 wkwebviewconfiguration *configuration = [[wkwebviewconfiguration alloc] init]; configuration.usercontentcontroller = usercontentcontroller; _webview = [[wkwebview alloc] initwithframe:cgrectzero configuration:configuration]; _webview.navigationdelegate = self; _webview.uidelegate = self; |
getkeyiosandroid_action upload_action 分別是h5通過message handler的方式來調(diào)用oc的兩個方法。
這時,就已經(jīng)發(fā)生了隱患,因為
[usercontentcontroller addscriptmessagehandler:self name:getkeyiosandroid_action];
這里usercontentcontroller持有了self ,然后 usercontentcontroller 又被configuration持有,最終唄webview持有,然后webview是self的一個私有變量,所以self也持有self,所以,這個時候有循環(huán)引用的問題存在,導(dǎo)致界面被pop或者dismiss之后依然會存在內(nèi)存中。不會被釋放
當(dāng)然如果你只是靜態(tài)界面,或者與h5的交互的內(nèi)容僅限于本頁面內(nèi)的內(nèi)容,其實(shí)只是單純的內(nèi)存泄漏,但是,如果此時和h5的交互方法中牽扯到全局變量,或者全局的一些內(nèi)容,那么就不可控制了。
我發(fā)現(xiàn)這個問題是因為我們web頁面會監(jiān)聽token過期的和登錄狀態(tài)改變的通知,然后會刷新界面,并且重新發(fā)送請求,這一系列動作中會和用戶的全局信息進(jìn)行交互,所以在訪問一個web頁面后,切換賬號登錄時會發(fā)現(xiàn)有之前訪問過的web頁面請求發(fā)出,并且因為token不同報了token過期的錯誤,所以導(dǎo)致登錄后誤操作為token過期,緊接著被踢到登錄界面。
通過charles抓包發(fā)現(xiàn),這些web頁面都是在切換登錄賬號欠訪問的所有界面,所以,鎖定問題時web頁面依舊存在,在切換登錄后收到了登錄狀態(tài)改變的通知,重新刷新了界面導(dǎo)致請求發(fā)出并返回報錯,進(jìn)而出現(xiàn)登錄后被踢出的bug。
解決方案:
既然是循環(huán)引用,那么必須破除一邊的強(qiáng)引用,改為弱引用,或者直接去除引用。思路明朗了。。
嘗試1:
1
2
3
|
id __weak weakself = self; wkusercontentcontroller *usercontentcontroller = [[wkusercontentcontroller alloc] init]; [usercontentcontroller addscriptmessagehandler:weakself name:getkeyiosandroid_action]; |
思路效仿block , 結(jié)果失敗
嘗試2:
在viewwilldisappear / viewdiddisappear 生命周期方法中調(diào)用
1
|
[_webview.configuration.usercontentcontroller removealluserscripts]; |
這算一個腦抽的嘗試,看文檔說明就懂了。自行略過
嘗試3:
不在初始化時添加scriptmessagehandler, 而是和notificenter/kvc一個思路
1
2
3
4
5
6
7
8
9
10
11
12
13
|
- ( void )viewwillappear:( bool )animated { [super viewwillappear:animated]; [_webview.configuration.usercontentcontroller addscriptmessagehandler:self name:getkeyiosandroid_action]; [_webview.configuration.usercontentcontroller addscriptmessagehandler:self name:upload_action]; } - ( void )viewwilldisappear:( bool )animated { [super viewwilldisappear:animated]; [_webview.configuration.usercontentcontroller removescriptmessagehandlerforname:getkeyiosandroid_action]; [_webview.configuration.usercontentcontroller removescriptmessagehandlerforname:upload_action]; } |
結(jié)果成功
小結(jié):
之前在使用wkwebview的時候很多blog的內(nèi)容都只是說了怎么添加message handler 但是并沒有高速大家有這個內(nèi)存泄漏的風(fēng)險,如果你只是頁面內(nèi)的數(shù)據(jù)調(diào)用你壓根都不會發(fā)現(xiàn)這個問題。
此坑已填!
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。
原文鏈接:https://blog.csdn.net/wxs0124/article/details/78402596