我有一个用例,根据是否存在属性值,可以创建或删除引用它的对象。我正在使用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
时被销毁时才应创建对象。
答案 0 :(得分:1)
这不是一个真正的错误,但更像是技术限制。插槽不得删除已连接信号的发送方。它必须使用deleteLater()
来避免执行返回到已删除的对象。基本上由于同样的原因,Loader
无法立即删除已加载的项目,因为active
属性可能绑定到从已加载的项目层次结构中控制的内容。
答案 1 :(得分:1)
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.
}
}
}
}