From 8d9f374065ece570a0b79526b4fe24e6df2bddbc Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Thu, 23 Feb 2017 20:55:30 +0100 Subject: [PATCH] fix(all): memory leaks fixes #10459 fixes #10416 fixes #10286 --- src/components/action-sheet/action-sheet-component.ts | 1 + src/components/menu/menu.ts | 2 +- src/components/refresher/refresher.ts | 1 + src/components/tabs/tabs.ts | 3 +-- src/gestures/drag-gesture.ts | 5 +++-- src/gestures/ui-event-manager.ts | 7 ++++++- src/navigation/nav-controller-base.ts | 7 ++----- src/navigation/view-controller.ts | 2 +- src/tap-click/ripple.ts | 4 ---- src/tap-click/tap-click.ts | 6 ++++-- src/transitions/page-transition.ts | 1 + src/transitions/transition-controller.ts | 5 +++-- src/transitions/transition.ts | 2 +- 13 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/components/action-sheet/action-sheet-component.ts b/src/components/action-sheet/action-sheet-component.ts index 21c3e48a3e..f129ac6abc 100644 --- a/src/components/action-sheet/action-sheet-component.ts +++ b/src/components/action-sheet/action-sheet-component.ts @@ -183,6 +183,7 @@ export class ActionSheetCmp { ngOnDestroy() { assert(this.gestureBlocker.blocked === false, 'gesture blocker must be already unblocked'); + this.d = null; this.gestureBlocker.destroy(); } } diff --git a/src/components/menu/menu.ts b/src/components/menu/menu.ts index 84adeedaa7..c1d2ef064e 100644 --- a/src/components/menu/menu.ts +++ b/src/components/menu/menu.ts @@ -516,7 +516,7 @@ export class Menu { this.isOpen = isOpen; this._isAnimating = false; - this._events.destroy(); + this._events.unlistenAll(); if (isOpen) { // Disable swipe to go back gesture this._gestureBlocker.block(); diff --git a/src/components/refresher/refresher.ts b/src/components/refresher/refresher.ts index 3484cb2d93..3b82dc34c2 100644 --- a/src/components/refresher/refresher.ts +++ b/src/components/refresher/refresher.ts @@ -503,6 +503,7 @@ export class Refresher { * @private */ ngOnDestroy() { + this._events.destroy(); this._gesture.destroy(); this._setListeners(false); } diff --git a/src/components/tabs/tabs.ts b/src/components/tabs/tabs.ts index 8ece2a60d7..a94768eef9 100644 --- a/src/components/tabs/tabs.ts +++ b/src/components/tabs/tabs.ts @@ -411,6 +411,7 @@ export class Tabs extends Ion implements AfterViewInit { if (opts.updateUrl !== false) { this._linker.navChange(DIRECTION_SWITCH); } + assert(this.getSelected() === selectedTab, 'selected tab does not match'); this._fireChangeEvent(selectedTab); }); } else { @@ -419,8 +420,6 @@ export class Tabs extends Ion implements AfterViewInit { } _fireChangeEvent(selectedTab: Tab) { - assert(this.getSelected() === selectedTab, 'selected tab does not match'); - selectedTab.ionSelect.emit(selectedTab); this.ionChange.emit(selectedTab); } diff --git a/src/gestures/drag-gesture.ts b/src/gestures/drag-gesture.ts index bce37e86d4..86b7c74c46 100644 --- a/src/gestures/drag-gesture.ts +++ b/src/gestures/drag-gesture.ts @@ -62,7 +62,7 @@ export class PanGesture { unlisten() { if (this.isListening) { this.gestute && this.gestute.release(); - this.events.destroy(); + this.events.unlistenAll(); this.isListening = false; } } @@ -71,7 +71,8 @@ export class PanGesture { this.gestute && this.gestute.destroy(); this.gestute = null; this.unlisten(); - this.element = null; + this.events.destroy(); + this.events = this.element = this.gestute = null; } pointerDown(ev: any): boolean { diff --git a/src/gestures/ui-event-manager.ts b/src/gestures/ui-event-manager.ts index 89fced70ce..4d826ff908 100644 --- a/src/gestures/ui-event-manager.ts +++ b/src/gestures/ui-event-manager.ts @@ -43,10 +43,15 @@ export class UIEventManager { } } - destroy() { + unlistenAll() { this.evts.forEach(unRegEvent => { unRegEvent(); }); this.evts.length = 0; } + + destroy() { + this.unlistenAll(); + this.evts = null; + } } diff --git a/src/navigation/nav-controller-base.ts b/src/navigation/nav-controller-base.ts index 72f1e7f07c..249facbfc3 100644 --- a/src/navigation/nav-controller-base.ts +++ b/src/navigation/nav-controller-base.ts @@ -723,7 +723,7 @@ export class NavControllerBase extends Ion implements NavController { if (transition.isRoot()) { // this is the root transition - // it's save to destroy this transition + // it's safe to destroy this transition this._trnsCtrl.destroy(transition.trnsId); // it's safe to enable the app again @@ -909,13 +909,10 @@ export class NavControllerBase extends Ion implements NavController { view._destroy(this._renderer); } - // purge stack - this._views.length = 0; - // release swipe back gesture and transition this._sbGesture && this._sbGesture.destroy(); this._sbTrns && this._sbTrns.destroy(); - this._sbGesture = this._sbTrns = null; + this._queue = this._views = this._sbGesture = this._sbTrns = null; // Unregister navcontroller if (this.parent && this.parent.unregisterChildNav) { diff --git a/src/navigation/view-controller.ts b/src/navigation/view-controller.ts index 91d39a0d07..49a94746cc 100644 --- a/src/navigation/view-controller.ts +++ b/src/navigation/view-controller.ts @@ -523,7 +523,7 @@ export class ViewController { this._cmp.destroy(); } - this._nav = this._cmp = this.instance = this._cntDir = this._cntRef = this._hdrDir = this._ftrDir = this._nb = this._onDidDismiss = this._onWillDismiss = null; + this._nav = this._cmp = this.instance = this._cntDir = this._cntRef = this._leavingOpts = this._hdrDir = this._ftrDir = this._nb = this._onDidDismiss = this._onWillDismiss = null; } /** diff --git a/src/tap-click/ripple.ts b/src/tap-click/ripple.ts index dec74a8b59..4740d55d2b 100644 --- a/src/tap-click/ripple.ts +++ b/src/tap-click/ripple.ts @@ -10,8 +10,6 @@ import { DomController } from '../platform/dom-controller'; * @private */ export class RippleActivator implements ActivatorBase { - protected _queue: HTMLElement[] = []; - protected _active: HTMLElement[] = []; protected highlight: Activator; constructor(app: App, config: Config, private dom: DomController) { @@ -52,8 +50,6 @@ export class RippleActivator implements ActivatorBase { return; } - this._active.push(activatableEle); - var j = activatableEle.childElementCount; while (j--) { var rippleEle: any = activatableEle.children[j]; diff --git a/src/tap-click/tap-click.ts b/src/tap-click/tap-click.ts index 74c0c51f96..ae49c5002d 100644 --- a/src/tap-click/tap-click.ts +++ b/src/tap-click/tap-click.ts @@ -221,11 +221,13 @@ export class TapClick { } -function getActivatableTarget(ele: HTMLElement) { +function getActivatableTarget(ele: HTMLElement): any { let targetEle = ele; for (let x = 0; x < 10; x++) { if (!targetEle) break; - if (isActivatable(targetEle)) return targetEle; + if (isActivatable(targetEle)) { + return targetEle; + } targetEle = targetEle.parentElement; } return null; diff --git a/src/transitions/page-transition.ts b/src/transitions/page-transition.ts index c0ac488ca2..2a9a06bdff 100644 --- a/src/transitions/page-transition.ts +++ b/src/transitions/page-transition.ts @@ -25,6 +25,7 @@ export class PageTransition extends Transition { destroy() { super.destroy(); + this.enteringPage && this.enteringPage.destroy(); this.enteringPage = null; } diff --git a/src/transitions/transition-controller.ts b/src/transitions/transition-controller.ts index 06956e465a..0d83a7887c 100644 --- a/src/transitions/transition-controller.ts +++ b/src/transitions/transition-controller.ts @@ -53,8 +53,9 @@ export class TransitionController { } destroy(trnsId: number) { - if (this._trns[trnsId]) { - this._trns[trnsId].destroy(); + const trans = this._trns[trnsId]; + if (trans) { + trans.destroy(); delete this._trns[trnsId]; } } diff --git a/src/transitions/transition.ts b/src/transitions/transition.ts index 62bb8e4a47..5c7f4e430f 100644 --- a/src/transitions/transition.ts +++ b/src/transitions/transition.ts @@ -45,7 +45,7 @@ export class Transition extends Animation { destroy() { super.destroy(); - this.enteringView = this.leavingView = this._trnsStart = null; + this.parent = this.enteringView = this.leavingView = this._trnsStart = null; } }