1

我有一个奇怪的问题,它隐藏在一个大型项目中的某个地方。到目前为止,我无法在MCVE中重现它,但是一旦成功,我就会将其上交。

这是一个非常简单的错误行为。基本上我有一个QtObjectwith 属性,我设置了初始值,如下所示:

测试对象.qml

QtObject {
    id: root
    property int val1: { console.log('set val', root); return 42 }
    Component.onCompleted: console.log('Constructed Object', this)
}

!!!在这个例子中,我不会重现错误!!!

我的项目中的输出现在是:

set val TestObj_QMLTYPE_44(0x33799fa8)
set val TestObj_QMLTYPE_44(0x33799fa8)
Constructed Object TestObj_QMLTYPE_44(0x33799fa8)

因此,虽然对象只创建一次,但初始属性分配执行了两次。
由于我不知道在哪里寻找罪魁祸首,我无法提供可重现的示例,但也许有人已经偶然发现了同样的情况并找到了解决方案。

解决方案将是有益的,因为此问题会导致某些对象的多个实例化,而我无法销毁这些对象。

4

1 回答 1

0

创建了错误报告: 也许他们找到了解决此问题的方法,而无需使用 hacky 变通办法

问题是循环引用:

创建对象时,循环引用会导致奇怪的行为。

TestObj1.qml

import QtQuick 2.0
QtObject {
    property Item paps
    property int myVal: { console.log('myVal'); paps.val }
}

TestObj2.qml

import QtQuick 2.0    
Item {
    id: root
    property int val: { console.log('set val', root); return 42 }
    Component.onCompleted: console.log('Constructed Object')

    TestObj1 {
        id: to1
        paps: root
    }
}

结果:

qml: myVal
qml: set val TestObj_QMLTYPE_4(0x2c0bafb0)
qml: set val TestObj_QMLTYPE_4(0x2c0bafb0)
qml: Constructed Object

造成这种情况的可能原因是,该语句{console.log('set val', root); return 42 }尚未被处理,当它已经分配给 时myVal,因此该语句被执行了两次。

虽然这在正常情况下没有问题,但它可能会导致问题,只要我们没有在这些属性中动态创建对象。

TestObj3.qml

import QtQuick 2.0

Item {
    id: root
    property QtObject obj: { console.log('set obj'); return objPrototype.createObject(root) }
    Component.onCompleted: console.log('Constructed Object', obj)

    TestObj4 {
        id: to1
        paps: root
    }

    Component {
        id: objPrototype
        QtObject {
            id: op
            Component.onCompleted: console.log('PropertyObject created', op)
        }
    }
}

TestObj4.qml

import QtQuick 2.0
QtObject {
    property Item paps
    property QtObject myObj: paps.obj

    Component.onCompleted: console.log(myObj)
}

结果:

qml: set obj
qml: PropertyObject created QObject(0x2c124708)
qml: set obj
qml: PropertyObject created QObject(0x2c1246f8)
qml: Constructed Object QObject(0x2c1246f8)
qml: QObject(0x2c1246f8)

所以你可以看到,这个对象确实被创建了两次。

有一些解决方法:

  1. 不要使用循环引用——但这会很无聊。
  2. 不要使用动态对象创建,因为它总是会产生问题- 我可以只创建对象,然后使用property alias obj: myObjectIDproperty QtObject obj: myObjectID. 这有一个缺点,如果组件是可重用的,用户就不能替换那个对象或者对象仍然被创建,浪费内存。
  3. Component.onCompleted如果属性仍然为空(未被可重用组件的用户覆盖),则分配属性。这有一个缺点,即对象不可用,创建时Can't read property ... of null会出现很多错误。他们希望不会破坏应用程序。
  4. 创建一个讨厌的绑定循环写:property QtObject obj: (obj ? obj : objPrototype.createObject(root))。它会发出警告,但是来吧。这只是一个绑定循环,将被检测和破坏。

这些变通办法没有什么好处,但也许有用。

于 2017-05-10T14:39:15.823 回答