iOS WKWebView中MessageHandler內(nèi)存泄漏問題的完美解決過程
背景
項(xiàng)目中使用了WKWebView替換了之前的UIWebView,牽扯到Hybird開發(fā),我們需要和H5交互,所以用到了WKWebViewConfiguration 中的 WKUserContentController
所以初始化代碼如下
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的兩個(gè)方法。
這時(shí),就已經(jīng)發(fā)生了隱患,因?yàn)?/p>
[userContentController addScriptMessageHandler:self name:GetKeyiOSAndroid_Action];
這里userContentController持有了self ,然后 userContentController 又被configuration持有,最終唄webview持有,然后webview是self的一個(gè)私有變量,所以self也持有self,所以,這個(gè)時(shí)候有循環(huán)引用的問題存在,導(dǎo)致界面被pop或者dismiss之后依然會(huì)存在內(nèi)存中。不會(huì)被釋放
當(dāng)然如果你只是靜態(tài)界面,或者與H5的交互的內(nèi)容僅限于本頁面內(nèi)的內(nèi)容,其實(shí)只是單純的內(nèi)存泄漏,但是,如果此時(shí)和H5的交互方法中牽扯到全局變量,或者全局的一些內(nèi)容,那么就不可控制了。
我發(fā)現(xiàn)這個(gè)問題是因?yàn)槲覀僿eb頁面會(huì)監(jiān)聽token過期的和登錄狀態(tài)改變的通知,然后會(huì)刷新界面,并且重新發(fā)送請(qǐng)求,這一系列動(dòng)作中會(huì)和用戶的全局信息進(jìn)行交互,所以在訪問一個(gè)web頁面后,切換賬號(hào)登錄時(shí)會(huì)發(fā)現(xiàn)有之前訪問過的web頁面請(qǐng)求發(fā)出,并且因?yàn)閠oken不同報(bào)了token過期的錯(cuò)誤,所以導(dǎo)致登錄后誤操作為token過期,緊接著被踢到登錄界面。
通過charles抓包發(fā)現(xiàn),這些web頁面都是在切換登錄賬號(hào)欠訪問的所有界面,所以,鎖定問題時(shí)web頁面依舊存在,在切換登錄后收到了登錄狀態(tài)改變的通知,重新刷新了界面導(dǎo)致請(qǐng)求發(fā)出并返回報(bào)錯(cuò),進(jìn)而出現(xiàn)登錄后被踢出的bug。
解決方案:
既然是循環(huán)引用,那么必須破除一邊的強(qiáng)引用,改為弱引用,或者直接去除引用。思路明朗了。。
嘗試1:
id __weak weakSelf = self; WKUserContentController *userContentController = [[WKUserContentController alloc] init]; [userContentController addScriptMessageHandler:weakSelf name:GetKeyiOSAndroid_Action];
思路效仿block , 結(jié)果失敗
嘗試2:
在viewWillDisappear / viewDidDisappear 生命周期方法中調(diào)用
[_webView.configuration.userContentController removeAllUserScripts];
這算一個(gè)腦抽的嘗試,看文檔說明就懂了。自行略過
嘗試3:
不在初始化時(shí)添加ScriptMessageHandler, 而是和Notificenter/KVC一個(gè)思路
- (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的時(shí)候很多blog的內(nèi)容都只是說了怎么添加Message Handler 但是并沒有高速大家有這個(gè)內(nèi)存泄漏的風(fēng)險(xiǎn),如果你只是頁面內(nèi)的數(shù)據(jù)調(diào)用你壓根都不會(huì)發(fā)現(xiàn)這個(gè)問題。
此坑已填!
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
IOS開發(fā)之多線程N(yùn)SThiread GCD NSOperation Runloop
這篇文章主要介紹了IOS多線程開發(fā),主要用到NSThiread、GCD、 NSOperation、Runloop,有詳細(xì)的原理解析和實(shí)例代碼,對(duì)多線程感興趣的同學(xué),可以參考下2021-04-04IOS數(shù)字鍵盤左下角添加完成按鈕的實(shí)現(xiàn)方法
這篇文章主要介紹了IOS數(shù)字鍵盤左下角添加完成按鈕的實(shí)現(xiàn)方法的相關(guān)資料,希望通過本文能實(shí)現(xiàn)類似這樣的功能,需要的朋友可以參考下2017-08-08IOS 開發(fā)之swift中UIView的擴(kuò)展使用的實(shí)例
這篇文章主要介紹了IOS 開發(fā)之swift中UIView的擴(kuò)展使用的實(shí)例的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09iOS將時(shí)間NSDate轉(zhuǎn)化為毫秒時(shí)間戳的方法示例
這篇文章主要給大家介紹了關(guān)于iOS將時(shí)間NSDate轉(zhuǎn)化為毫秒時(shí)間戳的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08IOS實(shí)現(xiàn)簽到特效(散花效果)的實(shí)例代碼
這篇文章主要介紹了IOS實(shí)現(xiàn)簽到特效(散花效果)的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-05-05