I was investigating a strange destruction of my UI elements, yesterday. The UI that QML was automatically generating would simply stop appearing. That UI is used to modify the more complex rendering objects. I added a console output statement inside the JS loop that is populating the UI frame. After a few minutes of using the UI: it showed that the upgraded meta-object dictionary stopped to provide all the values that I had pushed into it, at the start of the application. These values are not used in the C++ code, after being pushed into the meta-object dictionary and they are meant to be accessible through the whole application lifetime.
That obviously screams at the problem being with the QML garbage collector, so I researched the way the QML garbage collector works and found this page about the QDeclarativeEngine and object ownership. The idea of object ownership is simple: each object provided to QML can either be owned by QML or owned by the underlying C++. Any object owned by QML may be garbage collected when memory runs low. Any object owned by C++ is outside the influence of the garbage collector.
So far, so good. What I'm peeved about is the heuristic that sets the default ownership of objects:
The above exerpt is from the official Qt documentation. The exception stated in the last line really surprised me. I cannot imagine how inefficient it would be if every C++ function called from some JS function had to return primitive types or newly-allocated objects. I believe that in order to keep symmetry, a JS function that requests a new C++ object should find the correct place to release it. Here's an example:
function worker(objectClassName) {
var object = BMetaObject.construct(objectClassName);
object.process();
object.deleteLater();
}
For now, I change the object ownership change my JS loop so that the garbage collector doesn't wipe my persistent objects:
var editableProperties = BMetaObject.classProperty(className, "editableProperties");
BMetaObject.setObjectOwnership(editableProperties, 0);
if (editableProperties != lastValue) {
typeEditorModel.insert(0, {"className":localizedName, "customEditor":null,
"editableProperties":editableProperties});
lastValue = editableProperties;
}
...
Henceforth, I will remain mindful of the object ownership in QML! Hopefully, you'll avoid this pitfall.