I have a strange problem, that is burried somewhere within a large project. So far I was not able to reproduce it in a MCVE, but as soon as I succeed, I will turn it in.
It is quite a simple missbehavior. Basically I have an QtObject
with properties, that I set with initial values as such:
TestObj.qml
QtObject {
id: root
property int val1: { console.log('set val', root); return 42 }
Component.onCompleted: console.log('Constructed Object', this)
}
!!! With this example, I do not reproduce the error !!!
The output in my project would be now:
set val TestObj_QMLTYPE_44(0x33799fa8)
set val TestObj_QMLTYPE_44(0x33799fa8)
Constructed Object TestObj_QMLTYPE_44(0x33799fa8)
So, though the object is only created once, the initial property assignment is performed twice.
As I have no idea, where to look for the culprit, I can't produce a reproducable example, but maybe someone stumbled uppon the same situation already and found a solution.
A solution would be beneficial, as this issue results in multiple instantiations of some objects, that I can not destroy.
Created Bug-Report: maybe they find a way to solve this issue withouth hacky workarounds
The problem are circular references:
Circular references are resulting in a strange behavior when creating objects.
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
}
}
Result:
qml: myVal
qml: set val TestObj_QMLTYPE_4(0x2c0bafb0)
qml: set val TestObj_QMLTYPE_4(0x2c0bafb0)
qml: Constructed Object
The probalbe cause for this is, that the statement {console.log('set val', root); return 42 }
has not been processed, when it is allready assigned to myVal
, therefore that statement is executed twice.
While this is no problem in normal situations, it might lead to problems, as long as we don't have dynamically created objects in those properties.
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)
}
Result:
qml: set obj
qml: PropertyObject created QObject(0x2c124708)
qml: set obj
qml: PropertyObject created QObject(0x2c1246f8)
qml: Constructed Object QObject(0x2c1246f8)
qml: QObject(0x2c1246f8)
So you can see, the object is indeed created twice.
There are some workarounds:
property alias obj: myObjectID
or property QtObject obj: myObjectID
. This has the downside, that if the component is reusable, that the user can't replace that object or the object is still created, wasting memory.Component.onCompleted
if the property is still empty (not overwritten by the user of the reusable component). This has the downside, that the object is not available, uppon creation and a lot of Can't read property ... of null
errors will appear. They will hopefully don't break the app though.property QtObject obj: (obj ? obj : objPrototype.createObject(root))
. It will throw a warning, but c'mon. It's just a binding loop, that will be detected and broken.Nothing nice in those workarounds, but maybe something usable.