1. 程式人生 > >WKWebView中MessageHandler的內存泄漏問題解決過程

WKWebView中MessageHandler的內存泄漏問題解決過程

可控 oid sage ken del view removes 既然 rem

  背景
  
  項目中使用了WKWebView替換了之前的UIWebView,牽扯到Hybird開發,我們需要和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的方式來調用OC的兩個方法。
  
  這時,就已經發生了隱患,因為
  
  [userContentController addScriptMessageHandler:self name:GetKeyiOSAndroid_Action];
  
  這裏userContentController持有了self ,然後 userContentController 又被configuration持有,最終唄webview持有,然後webview是self的一個私有變量,所以self也持有self,所以,這個時候有循環引用的問題存在,導致界面被pop或者dismiss之後依然會存在內存中。不會被釋放
  
  當然如果你只是靜態界面,或者與H5的交互的內容僅限於本頁面內的內容,其實只是單純的內存泄漏,但是,如果此時和H5的交互方法中牽扯到全局變量,或者全局的一些內容,那麽就不可控制了。
  
  我發現這個問題是因為我們web頁面會監聽token過期的和登錄狀態改變的通知,然後會刷新界面,並且重新發送請求,這一系列動作中會和用戶的全局信息進行交互,所以在訪問一個web頁面後,切換賬號登錄時會發現有之前訪問過的web頁面請求發出,並且因為token不同報了token過期的錯誤,所以導致登錄後誤操作為token過期,緊接著被踢到登錄界面。
  
  通過charles抓包發現,這些web頁面都是在切換登錄賬號欠訪問的所有界面,所以,鎖定問題時web頁面依舊存在,在切換登錄後收到了登錄狀態改變的通知,重新刷新了界面導致請求發出並返回報錯,進而出現登錄後被踢出的bug。
  
  解決方案:
  
  既然是循環引用,那麽必須破除一邊的強引用,改為弱引用,或者直接去除引用。思路明朗了。。
  
  嘗試1:
  
  id __weak weakSelf = self;
  
  WKUserContentController *userContentController = [[WKUserContentController alloc] init];
  
  [userContentController addScriptMessageHandler:weakSelf name:GetKeyiOSAndroid_Action];
  
  1
  
  2
  
  3
  
  思路效仿block , 結果失敗
  
  嘗試2:
  
  在viewWillDisappear / viewDidDisappear 生命周期方法中調用
  
  [_webView.configuration.userContentController www.yibaoyule1.com removeAllUserScripts];
  
  1
  
  2
  
  這算一個腦抽的嘗試,看文檔說明就懂了。自行略過
  
  這裏寫圖片描述
  
  嘗試3:
  
  不在初始化時添加ScriptMessageHandler, 而是和Notificenter/KVC一個思路
  
  - (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 www.8555388.cn/ )animated {
  
  [super viewWillDisappear:animated];
  
  [_webView.configuration.userContentController removeScriptMessageHandlerForName:GetKeyiOSAndroid_Action];
  
  [_webView.configuration.userContentController www.471060.com removeScriptMessageHandlerForName:Upload_Action];
  
  結果成功
  
  小結:
  
  之前在使用WKWebView的時候很多blog的內容都只是說了怎麽添加Message Handler 但是並沒有高速大家有這個內存泄漏的風險,如果你只是頁面內的數據調用你壓根都不會發現這個問題。
  
  此坑已填!

WKWebView中MessageHandler的內存泄漏問題解決過程