将Loader.active设置为false不会立即释放项目

时间:2017-01-04 21:26:19

标签: qt qml qtquick2 loader

我有一个用例,根据是否存在属性值,可以创建或删除引用它的对象。我正在使用Loader,其中active属性绑定到属性,即当属性具有非null值时,加载器被激活,当它被设置为null时已停用。

然而问题是加载器没有立即释放它的项目,所以暂时该项引用null属性,因此无法访问数据,而将属性设置为null会触发重新评估结果在一群cannot read property x of null

简单的逻辑表明这不应该发生。所以我认为可能问题是绑定评估的顺序是错误的,导致在加载器被停用之前评估项目的绑定。所以我尝试删除active的绑定并手动设置它。然而问题仍然存在。

所以这里有一个最小的表示来说明发生了什么:

Window {
  id: main
  visible: true
  width: 500
  height: 300

  property QtObject object : QtObject {
    property QtObject subObject: null
  }

  QtObject {
    id: subo
    property int i : 1
  }

  Loader {
    id: ld
    active: false
    sourceComponent: Text {
      text: object.subObject.i
      font.pointSize: 20
    }
  }

  MouseArea {
    anchors.fill: parent
    onClicked: {
      if (object.subObject) {
        ld.active = false
        object.subObject = null
      } else {
        object.subObject = subo
        ld.active = true
      }
    }
  }
}

请注意,在这种情况下,加载器在属性设置为null之前显式停用,但是,每次发生这种情况时,我在控制台中出现类型错误:< / p>

qrc:/main.qml:25: TypeError: Cannot read property 'i' of null

这似乎不是正确的行为。也许是一个错误?或者我错过了什么?关于如何解决这个限制的任何建议?请注意,使用视图或转发器时会以某种方式避免这种情况。

更新:为了进一步澄清,在我的实际生产代码中,如果没有引用该属性,加载器的项目就不可能存在。因此,我们的想法是,只有当属性具有null以外的值并且在null时被销毁时才应创建对象。

4 个答案:

答案 0 :(得分:1)

这不是一个真正的错误,但更像是技术限制。插槽不得删除已连接信号的发送方。它必须使用deleteLater()来避免执行返回到已删除的对象。基本上由于同样的原因,Loader无法立即删除已加载的项目,因为active属性可能绑定到从已加载的项目层次结构中控制的内容。

答案 1 :(得分:1)

我昨天遇到过这个。我需要两个共享相同属性的Loader。在C ++类中,我逐个更新两个Loader的活动属性,这也会导致该问题。我的解决方案是使用Binding并进行如下设置:

Binding {
        target: contentItemAlias
        property: 'currentIndex'
        value: if (header.status == Loader.Ready) 
        header.item.currentIndex //ensure the current status is not null
        when: content.status === Loader.Ready // the content is ready
    }

实际上这可能对您没有帮助,但这是我的代码中的解决方案。我希望你能看到它并试试binding。祝你成功。 这是我项目的链接:https://github.com/begoat/qmlLive

答案 2 :(得分:0)

尽管QML对象&#39;对我来说并不是新鲜事。 destroy()deleteLater(),后者在下一个事件循环周期之前不会销毁对象,我希望这些对象在该点之后停止处理事件。

似乎对象继续生存了一段时间,并且它的绑定继续被评估,无法解决,因为与对象破坏不同,属性设置会立即发生。

由于项目中没有null的选项,我设法通过拥有全局虚拟数据对象并使用条件绑定来解决问题:

active: object.data // for loader

data: loader.active ? object.data : Globals.dummydata // in item

这似乎有效,在最后时刻为对象提供虚拟数据。

答案 3 :(得分:0)

您还可以使用Loader连接到onActiveChanged的{​​{1}} - 事件,并在那里打破绑定:

Loader {
    id: ld
    active: false
    sourceComponent: Text {
        text: object.subObject.i
        font.pointSize: 20

        Connections {
            target: ld
            onActiveChanged: {
                if (active) return
                text = text // This will overwrite the binding by the last value of the property itself.
            }
        }
    }
}