WKWebView中MessageHandler的内存泄漏问题解决过程

  背景
  
  项目中使用了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 但是并没有高速大家有这个内存泄漏的风险,如果你只是页面内的数据调用你压根都不会发现这个问题。
  
  此坑已填!

时间: 2024-11-12 02:51:30

WKWebView中MessageHandler的内存泄漏问题解决过程的相关文章

Android中常见的内存泄漏

为什么会产生内存泄漏? 当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏. 内存泄漏对程序的影响? 内存泄漏是造成应用程序OOM的主要原因之一!我们知道Android系统为每个应用程序分配的内存有限,而当一个应用中产生的内存泄漏比较多时,这就难免会导致应用所需要的内存超过这个系统分配的内存限额,这就造成了内存溢出而导致应用Crash. Android中常见的内存泄漏汇总 1

Android 中如何分析内存泄漏

前提条件: 1,电脑安装了java 运行环境 2,手机端开启了 USB 调试开关 3,获取 root 权限 4,安装MAT工具,下载地址:http://www.eclipse.org/mat/downloads.php 基本步骤: 1,使用eclipse 自带的 DDMS 工具分析各线程的内存使用情况,如下图所示 Heap视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化. 怎样判断当前进程是否有内存泄漏呢? 这里需要注意一个值:VM Heap页面中部有一个data obje

Java中如何防止内存泄漏的发生

在Java开发中我们常常会遇到内存泄漏的情况发生.那么为什么会发生内存泄漏,以及怎样去防止! 内存泄漏的定义:对象已经没有被应用程序使用,但是垃圾回收器没办法移除它们,因为还在被引用着. 为什么会发生内存泄漏.下面这个例子中,A对象引用B对象,A对象的生命周期(t1-t4)比B对象的生命周期(t2-t3)长的多.当B对象没有被应用程序使用之后,A对象仍然在引用着B对象.这样,垃圾回收器就没办法将B对象从内存中移除,从而导致内存问题,因为如果A引用更多这样的对象,那将有更多的未被引用对象存在,并消

String中substring方法内存泄漏问题

众所周知,JDK中以前String类中的substring方法存在内存泄漏问题,之所以说是以前,是因为JDK1.7及以后的版本已经修复了,我看都说JDK1.6的版本也存在这个问题,但是我本机上安装的1.6看了看源码不存在内存泄漏问题啊,又看了1.7的源码,和我本机的1.6的一样,是不是我的1.6版版其实是1.7的?!唉,不管了,反正1.7版本肯定没有这个问题(1.5及更老版本肯定有)了,大家就放心的用吧. 之所以存在内存泄漏的问题,是因为原先的版本中,substring是这样实现的: publi

.NET中常见的内存泄漏和解决办法

在.NET中,虽然CLR的GC垃圾回收器帮我们自动回收托管堆对象,释放内存,最大程度避免了"内存泄漏"(应用程序所占用的内存没有得到及时释放),但.NET应用程序"内存泄漏"的问题还是会存在,如果不加以注意,"内存泄漏"时有发生. 有关流以及Reader或Writer引起的内存泄漏 比如,把文件读取到流中: public static string ReadFile() { var filePath = @"硬盘地址"; va

java中会存在内存泄漏吗

内存泄漏是指不再被使用的对象或者变量一直被占据在内存中.但是java中有垃圾回收机制,它能够将不再被使用的对象,自动从内存中清除. 即使这样,java中也存在着内存泄漏的情况: 一:当长生命周期的对象持有短生命周期的对象的引用,就很可能发生内存泄漏.尽管短生命周期的对象已经不再需要,但是长生命周期的对象一直持有它的引用导致其无法被回收.例如,缓存系统:加载一个对象放在缓存系统中,一直不去使用这个对象,但是它一直被缓存引用,所以不会被回收导致缓存泄漏. 检查java中的内存泄漏,一定要将程序各个分

【Java面试题】52 java中会存在内存泄漏吗,请简单描述。

所谓内存泄露就是指一个不再被程序使用的对象或变量一直被占据在内存中.Java中有垃圾回收机制,它可以保证一对象不再被引用的时候,即对象编程了孤儿的时候,对象将自动被垃圾回收器从内存中清除掉.由于Java 使用有向图的方式进行垃圾回收管理,可以消除引用循环的问题,例如有两个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的. package com.huawei.interview; import java.io.IOException; public class Garbage

Java 中会存在内存泄漏吗,请简单描述。

答: 理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因):然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生.例如Hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露.下面例子中的代码也会导致内存泄露. import java.u

Android内存泄漏的检测流程、捕捉以及分析

https://blog.csdn.net/qq_20280683/article/details/77964208 简述: 一个APP的性能,重度关乎着用户体验,而关于性能检测的一个重要方面,就是内存泄漏,通常内存泄漏的隐藏性质比较强,不同于异常导致的程序Crash,在异常导致的Crash中,我们能够及时的发现程序问题的存在,并通过log日志定位到问题所在的具体位置,然后及时进行解决,而内存泄漏则不同,在APP中存在内存泄漏的情况下,用户在低频率短时间的使用中,并不能察觉到有什么异样,反之,随