【问题标题】:Titanium Application events firing after controller is destroyed控制器被销毁后触发的 Titanium 应用程序事件
【发布时间】:2013-07-06 10:59:41
【问题描述】:
  • 应用类型:移动
  • 钛 SDK:3.1.1.GA
  • 平台和版本:iOS 6.1
  • 设备:iOS 模拟器
  • 主机操作系统:OSX 10.8.4
  • 钛工作室:3.1.1.201306112235

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);
});

前言:上面的代码被淡化以证明一个观点。我知道它并没有真正做任何事情,但它确实有问题。

parent_controller.js 中的代码可以根据我的 Titanium Mobile iPad 应用程序中的用户交互执行多次。如果上面的代码只在一切正常后运行。每次上面的代码再次运行时,以前的控制器都会在内存中剩余一些,并且仍在捕获事件。

例如,假设在第一次执行代码时生成了 3 个inventory_list_row 控制器。在控制台中,我将看到 3 条“签入”消息按预期出现。但是,第二次运行时,我会在控制台中看到 6 条“签入”消息,依此类推。

为什么会这样,我能做些什么来防止这种情况发生?您可以看到我已经尝试使用 .destroy 并将 row 设置为 null 无济于事。

【问题讨论】:

    标签: titanium appcelerator titanium-mobile appcelerator-mobile titanium-alloy


    【解决方案1】:
    • 您可能需要在 控制器。
    • 为什么要使用全局事件侦听器进行本地事件管理?
    • 也许您可以改用回调

    这些只是一些快速观察,无需我编写任何代码来验证。老实说,我根本不使用全局事件。

    【讨论】:

      【解决方案2】:

      这是一个快速修复,实现 Aaron 在他的第一个项目符号中所说的,只需将此方法添加到您的库存行控制器。

      // 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();
      }
      

      全局事件侦听器会一直存在,直到您删除它们,这意味着(根据 javascript 范围规则)它们访问的 任何 变量也会自动保持不变。由于您在事件侦听器中访问args.data.title,并且此变量的范围为inventory_list_row 控制器,因此无论您做什么,解释器都会将控制器(或其中大部分)保留在内存中,因此这些事件将继续触发在你摧毁它们并将它们归零之后很久。

      我根本不会使用全局事件侦听器,在内存稀缺的环境中,太多的范围混淆和内存泄漏的可能性。采纳 Aaron 的建议并基于此回调,或在控制器本身上触发本地事件。

      编辑:

      如果您只希望该侦听器“侦听”一次,则可以这样做,只需立即将其删除,很简单:

      Ti.App.addEventListener('checkIn', function(e) {
          console.info('Checking In: ' + args.data.title);
          Ti.App.removeEventListener(this);
      });
      

      【讨论】:

      • 正如我在下面提到的,“删除destroy方法中的eventListener”将完全按照您在此处所做的操作,只是它将使用Alloy控制器默认提供的destroy方法
      • @AaronSaunders 更新了我的答案...我有点不清楚如何覆盖destroy,但希望能仔细检查
      猜你喜欢
      • 1970-01-01
      • 2017-12-31
      • 1970-01-01
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-09
      相关资源
      最近更新 更多