iOS: Memory leak on iOS ListView when template contains event listener.
(Similar to Android issue TIMOB-13747)
- Run the app below in Instruments and profile memory usage
- With every opening of the window containing the list view, 8 TiUILabelProxy and 4 TiUIListItemProxy objects are allocated and never freed again.
var baseWin = Ti.UI.createWindow({backgroundColor: 'red'});
var b = Ti.UI.createButton({
title: 'Click',
color: 'red',
selectedColor: 'blue',
height: '100dp',
width: '150dp',
backgroundImage: 'appicon.png',
backgroundColor: 'green',
style: Titanium.UI.iPhone ? Titanium.UI.iPhone.SystemButtonStyle.PLAIN : 0
});
b.addEventListener('click', function(evt) {
var win = Ti.UI.createWindow({backgroundColor: 'white'});
// Create a custom template that displays an image on the left,
// then a title next to it with a subtitle below it.
var myTemplate = {
childTemplates: [
{ // Title
type: 'Ti.UI.Label', // Use a label for the title
bindId: 'info', // Maps to a custom info property of the item data
properties: { // Sets the label properties
color: 'black',
font: { fontFamily:'Arial', fontSize: '20dp', fontWeight:'bold' },
left: '60dp', top: 0,
},
events: {
'click': function(evt) {
var item = evt.section.getItemAt(evt.itemIndex);
item.info.text = 'Clicked';
evt.section.updateItemAt(evt.itemIndex, item);
}
}
},
{ // Subtitle
type: 'Ti.UI.Label', // Use a label for the subtitle
bindId: 'es_info', // Maps to a custom es_info property of the item data
properties: { // Sets the label properties
color: 'gray',
font: { fontFamily:'Arial', fontSize: '14dp' },
left: '60dp', top: '25dp',
}
}
]
};
var listView = Ti.UI.createListView({
// Maps myTemplate dictionary to 'template' string
templates: { 'template': myTemplate },
// Use 'template', that is, the myTemplate dict created earlier
// for all items as long as the template property is not defined for an item.
defaultItemTemplate: 'template'
});
var sections = [];
var fruitSection = Ti.UI.createListSection({ headerTitle: 'Fruits / Frutas'});
var fruitDataSet = [
// the text property of info maps to the text property of the title label
// the text property of es_info maps to text property of the subtitle label
// the image property of pic maps to the image property of the image view
{ info: {text: 'Apple'}, es_info: {text: 'Manzana'}, pic: {image: 'apple.png'}},
{ info: {text: 'Banana'}, es_info: {text: 'Banana'}, pic: {image: 'banana.png'}}
];
fruitSection.setItems(fruitDataSet);
sections.push(fruitSection);
var vegSection = Ti.UI.createListSection({ headerTitle: 'Vegetables / Verduras'});
var vegDataSet = [
{ info: {text: 'Carrot'}, es_info: {text: 'Zanahoria'}, pic: {image: 'carrot.png'}},
{ info: {text: 'Potato'}, es_info: {text: 'Patata'}, pic: {image: 'potato.png'}}
];
vegSection.setItems(vegDataSet);
sections.push(vegSection);
listView.setSections(sections);
var button = Ti.UI.createButton({
title: 'Close Window',
color: 'black',
height: '100dp',
width: '150dp',
backgroundColor: 'green',
});
button.addEventListener('click', function(evt) {
win.close();
win.remove(listView);
listView = null;
win.remove(button);
button = null;
win = null;
});
win.add(listView);
win.add(button);
win.open();
});
baseWin.add(b);
baseWin.open();
Hello! Can you please remove the elements of the window, then null them after closing it? Check this sample: https://gist.github.com/mauropm/5923980 Right now, your code says "I will close this window, but I didn't null it, so I can reopen it if I want". Best, Mauro
Hi Mauro Thanks for your input. I have changed my test app in the following way:
When I do this, the leak goes away. However, if I change the event listener to
and I click on the "info" label, I have the memory leak again. The memory leak does not occur if I do not click the "info" label. Any further suggestions? (I will adjust the description in this item to reflect the new test app.) Many thanks & regards, Philippe
Hello! In the second example of click, please remove the event from the label before nulling it. Remember: in order to remove an event, you have not to use anonymous functions, but named ones, so it will be easier. Right now your object is holding in memory because it does have an event listener attached. BTW, the GC won't usually kick in all time. You need to repeat your testing a lot of times, so the memory reach a memory warning or similar, so that will force the GC to clean the memory. Best, Mauro
Hi Mauro {quote} In the second example of click, please remove the event from the label before nulling it. {quote} In my understanding, I do not have direct access to the objects created by a list item, so how can I remove the event listener on the label? Do you mean that I should remove the 'click' event listener from the template used in the ListView? I tried this (see code below), but this did not fix the problem. Any further ideas? Many thanks & regards, Philippe
Closing ticket as duplicate.