Reputation: 594
parent_controller.js:
_.each(category, function(inventory_item, index, list) {
var row = Alloy.createController('inventory_list_row', {
selectedBackgroundColor: '',
data: inventory_item
});
row.destroy();
row = null;
});
Ti.App.fireEvent('checkIn');
inventory_list_row.js:
Ti.App.addEventListener('checkIn', function(e) {
console.info('Checking In: ' + args.data.title);
});
Preface: The above code is watered down to prove a point. I know it's doesn't really do anything, but it does prove problematic.
The code in parent_controller.js can be executed multiple times based upon user interaction in my Titanium Mobile iPad application. If the code above only runs once everything is fine. Each time the code above runs again the previous controllers are some how remaining in memory and are still trapping events.
For example, let's say there are 3 inventory_list_row controllers generated the first time the code is executed. In the console I'll see 3 'Checking In' messages appear as expected. The second time it runs, though, I'll see 6 'Checking In' messages appear in the console, so on and so forth.
Why is this, and what can I do to prevent this? You can see I've tried using .destroy and setting row to null to no avail.
Upvotes: 4
Views: 3686
Reputation: 6095
Heres a quick fix, implementing what Aaron said in his first bullet, just add this method to your inventory row controller.
// Here is the event listener function
var checkInListenFunction = function(e) {
console.info('Checking In: ' + args.data.title);
}
// Add just like in your code
Ti.App.addEventListener('checkIn', checkInListenFunction);
// When this controller is destroyed you have to remove the listener as well
// OR the controller will forever stay in memory, since you access variables
// from the controllers scope!
exports.destroy = function() {
// Remove the listener first
Ti.App.addRemoveListener('checkIn', checkInListenFunction);
$.destroy();
}
Global event listeners persist until you remove them, that means that (according to javascript scope rules) any variable they access is automatically persisted as well. Since you access args.data.title
inside your event listener, and this variable is scoped to the inventory_list_row
controller, the interpreter keeps the controller (or most of it) around in memory no matter what you do, so these events will continue to fire long after you destroy and null them out.
I would not use global event listeners at all, too much scope confusion and potential for memory leaks in a memory scarce environment. Take Aaron's suggestions and make this callback based, or fire a local event on the controller itself.
EDIT:
You could do this if you only want that listener to "listen" one time, just remove it immediately, simple:
Ti.App.addEventListener('checkIn', function(e) {
console.info('Checking In: ' + args.data.title);
Ti.App.removeEventListener(this);
});
Upvotes: 0
Reputation: 33345
These are just some quick observations without me writing any code to veryify. Honestly I do not use global events at all.
Upvotes: 1