如果不知道如何集成flutter可以看我的上一篇文章《iOS老项目集成flutter最新混编方案》
集成flutter进入项目后发现每次进入flutter模块都是导致内存增加60M-80M并且退出flutter页面后,内存并不会释放,具体原因是由于每次进入Flutter页面都会创建新的的FlutterViewController,但退出的时候并没有释放。
为什么google难以解决:
由于整个FlutterEngine是用MRC的方式编写,所以内存管理比较困难,每个变量生成retain,都需要被release,如果一个实例retain了两次,只release一次,也会导致无法释放,如果设置了autorelease,就有可能提前释放,导致badasses,访问野指针。
客观原因,一般的应用只会创建一个flutter应用,或者干脆就直接都是flutter应用,不释放就不释放,多点内存也无所谓,不影响崩溃,不影响使用,所以google照常发布1.0版。
官方发布最新的解决方案,使用FlutterEngine初始化FlutterViewController
FlutterViewController *flutterViewController = [[FlutterViewControlleralloc]initWithEngine:flutterEnginenibName:nilbundle:nil];
通过类别发现,此方案确实使FlutterViewController释放,但拒网上查询资料得知google团队只是将内存泄漏转嫁到FlutterEngine对象上,并没有彻底解决内存问题,实践发现,每次打开Flutter页面内存会增长不到1M左右,与之前暴涨的80M内存相比,此方案还是在可接受范围。
有大神彻底解决内存泄漏的问题,通过自己修改frameword的方式,有兴趣的可以了解下相关文章。传送门
但是这个方案有个致命的缺陷,就是每次flutter升级都需要下载最新的frameword文件,对于没有能力自己编写frameword文件的同学,我更加倾向于官方的解决方案,不到1M的内存泄漏还是在可以接受的范围内的。
官方方案:
但是,使用官方解决方案发现我们想通过[flutterViewControllersetInitialRoute:@"route1"];通过不同的routename加载不同flutter页面不再生效,原因是在AppDelegate中运行[self.flutterEnginerunWithEntrypoint:nil];这行代码的时候,flutter已经初始化好了,这时在flutter中通过window.defaultRouteName获取到的route一直是默认的/,为了解决可以加载不同flutter页面的问题,我通过native向flutter发送消息,flutter接受到消息后加载不同页面的方法来解决。
这时问题又来了,flutter中调用eventChannel.receiveBroadcastStream(postArg).listen(onData ,onError: onError);时,OC代码中的FlutterEventChannel还未运行到,这就导致eventSink绑定不成功,所以[flutterEngine runWithEntrypoint:nil];与FlutterEventChannel对象必须同时生成,我是通过单例解决这一问题的:
项目启动初始化单例,如果等到点击进入flutter页面的时候再初始化单例,这时[flutterEngine runWithEntrypoint:nil];运行,flutter刚刚创建会导致跳转时页面会白2-3秒,所以在项目初始化时,将flutter也初始化。