QML garbage collection deletes objects still in use
Solution 1:
I've encountered this problem on several occasions, with objects created dynamically, regardless of whether they were created in QML or C++
Objects are only considered for garbage collection if they have JavaScriptOwnership set, which is the case if they are
- Directly created by JavaScript/QML
- Ownership is explicitly set to JavaScriptOwnership
- The object is returned from a Q_INVOKABLE method and didn't have setObjectOwnership() called on it previously.
In all other cases objects are assumed to be owned by C++ and not considered for garbage collection.
At first I assumed it may be an issue with parenting, since I was using QObject derived classes, and the QML method of dynamic instantiation passes an Item for a parent, whereas QtObject doesn't even come with a parent property - it is not exposed from QObject.
The Qt object tree is completely different from the Qml object tree. QML only cares about its own object tree.
delegate: Item {
id: p
width: childrenRect.width
height: childrenRect.height
Component.onCompleted: Qt.createComponent("Uimain.qml").createObject(p, {"object" : o})
}
The combination of dynamically created objects in the onCompleted handler of a delegate is bound to lead to bugs.
When you collapse the tree, the delegates get destroyed, and with them all of their children, which includes your dynamically created objects. It doesn't matter if there are still live references to the children.
Essentially you've provided no stable backing store for the tree - it consists of a bunch of nested delegates which can go away at any time.
Now, there are some situations where QML owned objects are unexpectedly deleted: any C++ references don't count as a ref for the garbage collector; this includes Q_PROPERTYs. In this case, you can:
- Set CppOwnership explicitly
- Use QPointer<> to hold the reference to deal with objects going away.
- Hold an explicit reference to the object in QML.