Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-5465] iOS: Tapping Tab Orphans Windows on Tab's Stack

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2011-10-10T09:17:09.000+0000
Affected Version/sRelease 1.8.0
Fix Version/sSprint 2011-41, Release 1.8.0
ComponentsiOS
Labelsbranch-5062, module_tabgroup, qe-testadded
ReporterDawson Toth
AssigneeStephen Tramer
Created2011-10-07T01:29:45.000+0000
Updated2014-06-19T12:46:32.000+0000

Description

Problem

Tapping the tab's button to return to the root window of the tab orphans any windows between the current window and the root window.

Why This Is A Problem

Orphaned windows equate to leaked memory.

Expected Behavior

Tapping the tab's button should close every window that is open on that tab's stack, not just the current window.

Reproduction

Drop the following in an app.js. Touch "S1: Touch Me", then "S2: Touch Me". Notice in the log which windows were opened, and which were closed.
var tabGroup = Ti.UI.createTabGroup();

function openWindowOnStack(i) {
    var win = Ti.UI.createWindow({
        title: 'I Am ' + i
    });
    win.addEventListener('open', function() {
        Ti.API.info('opened ' + i + '!');
        if (i < 4) {
            openWindowOnStack(i + 1);
        }
    });
    win.addEventListener('close', function() {
        Ti.API.info('closed ' + i + '!');
    });
    tab.open(win);
}

var outer = Ti.UI.createWindow({
    title: 'I Am Parent',
    rightNavButton: Ti.UI.createButton({ title: 'S1: Touch Me' })
});
var tab = Ti.UI.createTab({
    window: outer, title: 'S2: Touch Me'
});
tabGroup.addTab(tab);

outer.rightNavButton.addEventListener('click', function() {
    openWindowOnStack(0);
});

tabGroup.open();

Current Output

[INFO] opened 0!
[INFO] opened 1!
[INFO] opened 2!
[INFO] opened 3!
[INFO] opened 4!
[INFO] closed 4!

Expected Output

[INFO] opened 0!
[INFO] opened 1!
[INFO] opened 2!
[INFO] opened 3!
[INFO] opened 4!
[INFO] closed 3!
[INFO] closed 2!
[INFO] closed 1!
[INFO] closed 0!

Comments

  1. Dawson Toth 2011-10-10

    Workaround

    By following the three rules at the top of this app.js, I am able to clean up any orphaned windows.
       /*
        To keep track of and clean up windows that have been opened on a specific tab, you must do the following:
        - Whenever you open a window, use the "openInTab(tab, win)" function.
        - On every window, listen for its "close" event and call the "trackClosedWindow(tab, win)" function.
        - Whenever you want to close all but the root window of a tab, call the "closeAllInTab(tab)" function.
        - Whenever a root window gains focus, it must call "closeAllInTab(tab)" on its tab.
        */
       
       function openWindowOnStack(i) {
           var win = Ti.UI.createWindow({
               title: 'Window ' + i
           });
           win.addEventListener('open', function(evt) {
               Ti.API.info('Opened: ' + evt.source.title);
               if (i < 4) {
                   openWindowOnStack(i + 1);
               }
           });
           win.addEventListener('close', function(evt) {
               Ti.API.info('Closed: ' + evt.source.title);
               trackClosedWindow(tab, evt.source);
           });
           openInTab(tab, win);
       }
       
       var outer = Ti.UI.createWindow({
           title: 'Root Window',
           rightNavButton: Ti.UI.createButton({ title: 'S1: Touch Me' })
       });
       outer.addEventListener('focus', function() {
           // Make sure all children have closed...
           closeAllInTab(tab);
       });
       outer.rightNavButton.addEventListener('click', function() {
           openWindowOnStack(0);
       });
       
       function trackClosedWindow(tab, window) {
           var windows = tab.windows || [];
           // Iterate through backwards because windows further down the tree are more likely to be removed.
           for (var w = windows.length - 1; w >= 0; w--) {
               if (windows[w] == window) {
                   windows[w] = null;
                   windows.splice(w, 1);
                   break;
               }
           }
           tab.windows = windows;
       }
       function closeAllInTab(tab) {
           var windows = tab.windows || [];
           // Iterate through forwards because we want to close the most recent window last for a nice animation to the root.
           for (var w = 0; w < windows.length; w++) {
               windows[w].close();
               windows[w] = null;
           }
           tab.windows = windows = [];
       }
       function openInTab(tab, window) {
           var windows = tab.windows || [];
           windows.push(window);
           tab.open(window);
           tab.windows = windows;
       }
       
       var tabGroup = Ti.UI.createTabGroup();
       var tab = Ti.UI.createTab({
           window: outer,
           title: 'S2. Touch Me'
       });
       tabGroup.addTab(tab);
       tabGroup.open();
       
  2. Thomas Huelbert 2011-11-04

    note to QE - this may not fit easily into current template.
  3. Michael Pettiford 2011-12-08

    Tested on Ti Studio 1.0.7.201112080131 
Ti Mob SDK 1.8.0.1.v20111208124750 
OSX Lion iPhone 4S OS 5.0.1 Expected behavior is shown

JSON Source