如果不知道如何集成flutter可以看我的上一篇文章《iOS老項(xiàng)目集成flutter最新混編方案》
集成flutter進(jìn)入項(xiàng)目后發(fā)現(xiàn)每次進(jìn)入flutter模塊都是導(dǎo)致內(nèi)存增加60M-80M并且退出flutter頁(yè)面后,內(nèi)存并不會(huì)釋放,具體原因是由于每次進(jìn)入Flutter頁(yè)面都會(huì)創(chuàng)建新的的FlutterViewController,但退出的時(shí)候并沒(méi)有釋放。
為什么google難以解決:
由于整個(gè)FlutterEngine是用MRC的方式編寫(xiě),所以內(nèi)存管理比較困難,每個(gè)變量生成retain,都需要被release,如果一個(gè)實(shí)例retain了兩次,只release一次,也會(huì)導(dǎo)致無(wú)法釋放,如果設(shè)置了autorelease,就有可能提前釋放,導(dǎo)致badasses,訪問(wèn)野指針。
客觀原因,一般的應(yīng)用只會(huì)創(chuàng)建一個(gè)flutter應(yīng)用,或者干脆就直接都是flutter應(yīng)用,不釋放就不釋放,多點(diǎn)內(nèi)存也無(wú)所謂,不影響崩潰,不影響使用,所以google照常發(fā)布1.0版。
官方發(fā)布最新的解決方案,使用FlutterEngine初始化FlutterViewController
FlutterViewController *flutterViewController = [[FlutterViewControlleralloc]initWithEngine:flutterEnginenibName:nilbundle:nil];
通過(guò)類(lèi)別發(fā)現(xiàn),此方案確實(shí)使FlutterViewController釋放,但拒網(wǎng)上查詢資料得知google團(tuán)隊(duì)只是將內(nèi)存泄漏轉(zhuǎn)嫁到FlutterEngine對(duì)象上,并沒(méi)有徹底解決內(nèi)存問(wèn)題,實(shí)踐發(fā)現(xiàn),每次打開(kāi)Flutter頁(yè)面內(nèi)存會(huì)增長(zhǎng)不到1M左右,與之前暴漲的80M內(nèi)存相比,此方案還是在可接受范圍。
有大神徹底解決內(nèi)存泄漏的問(wèn)題,通過(guò)自己修改frameword的方式,有興趣的可以了解下相關(guān)文章。傳送門(mén)
但是這個(gè)方案有個(gè)致命的缺陷,就是每次flutter升級(jí)都需要下載最新的frameword文件,對(duì)于沒(méi)有能力自己編寫(xiě)frameword文件的同學(xué),我更加傾向于官方的解決方案,不到1M的內(nèi)存泄漏還是在可以接受的范圍內(nèi)的。
官方方案:
但是,使用官方解決方案發(fā)現(xiàn)我們想通過(guò)[flutterViewControllersetInitialRoute:@"route1"];通過(guò)不同的routename加載不同flutter頁(yè)面不再生效,原因是在AppDelegate中運(yùn)行[self.flutterEnginerunWithEntrypoint:nil];這行代碼的時(shí)候,flutter已經(jīng)初始化好了,這時(shí)在flutter中通過(guò)window.defaultRouteName獲取到的route一直是默認(rèn)的/,為了解決可以加載不同flutter頁(yè)面的問(wèn)題,我通過(guò)native向flutter發(fā)送消息,flutter接受到消息后加載不同頁(yè)面的方法來(lái)解決。
這時(shí)問(wèn)題又來(lái)了,flutter中調(diào)用eventChannel.receiveBroadcastStream(postArg).listen(onData ,onError: onError);時(shí),OC代碼中的FlutterEventChannel還未運(yùn)行到,這就導(dǎo)致eventSink綁定不成功,所以[flutterEngine runWithEntrypoint:nil];與FlutterEventChannel對(duì)象必須同時(shí)生成,我是通過(guò)單例解決這一問(wèn)題的:
項(xiàng)目啟動(dòng)初始化單例,如果等到點(diǎn)擊進(jìn)入flutter頁(yè)面的時(shí)候再初始化單例,這時(shí)[flutterEngine runWithEntrypoint:nil];運(yùn)行,flutter剛剛創(chuàng)建會(huì)導(dǎo)致跳轉(zhuǎn)時(shí)頁(yè)面會(huì)白2-3秒,所以在項(xiàng)目初始化時(shí),將flutter也初始化。