Как управлять временем жизни динамически распределенного QObject, возвращаемого в QML?

У меня есть этот код:

QVariant componentFromCode(QString code) {
 QQmlComponent * component = new QQmlComponent(engine);
 engine->setObjectOwnership(component, QQmlEngine::JavaScriptOwnership);
 connect(component, &QQmlComponent::destroyed, this, &Factory::echo);
 component->setData(code.toUtf8(), QUrl());
 return QVariant::fromValue(component);
}

Но Factory::echo() никогда не вызывается, что означает, что объект просачивается каждый раз при вызове функции.

Это то, что у меня есть на стороне QML:

onClicked: { 
 var code =
 'import QtQuick 2.3
 Rectangle {
 width: 50
 height: 50
 color: "blue"
 }
 '
 stack.push(Factory.componentFromCode(code))
 gc()
}

Я явно устанавливаю принадлежность объекта и явно вызываю gc() для принудительной сборки мусора, но сигнал destroyed() никогда не испускается, поэтому объект никогда не удаляется. Из того, что я прочитал, это должно произойти автоматически в QML.

Обратите внимание, что он работает с:

var comp = Factory.componentFromCode(code)
stack.push(comp)
comp.destroy()

Но это просто не удобно, я бы хотел, чтобы объект был уничтожен автоматически по мере того, как он выпал из области видимости, или, альтернативно, оставался в живых до тех пор, пока на него ссылается код QML и будет уничтожен, когда он больше не будет необходимо, что может быть трудно/абсурдно делать вручную во многих ситуациях.

EDIT: пример стека оказался моим фактическим кодом, но я полагаю, что это не так хорошо, если предположить, как принимается стек, взявший на себя ответственность над компонентом. Я не получаю никакого управления жизненным циклом даже в таких простых случаях, как:

function JSfoo() {
 var obj = CXTProp.getCppQObjectStar()
 console.log(obj.objectName)
} // QObject is not collected here

или...

QtObject {
 property QtObject: CXTProp.getCppQObjectStar()
} // QObject is not collected after the object is destroyed
1 ответ

Я не думаю, что объект протекает. Попробуйте это:

class TestObj : public QObject {
 Q_OBJECT
public:
 ~TestObj() { qDebug() << "destructor called"; }
};
class Test : public QObject {
 Q_OBJECT
public:
 explicit Test(QObject *parent = 0) : QObject(parent) {}
public slots:
 QVariant getObject() {
 QObject * obj = new TestObj;
 obj->setObjectName("that object");
 connect (obj, &TestObj::destroyed, this, &Test::echo);
 return QVariant::fromValue(obj);
 }
 void echo() { qDebug() << "it got destroyed"; }
};

и в QML:

function test() {
 var test = Test.getObject()
 console.log(test.objectName)
}

После test() объект не будет собран, и когда вы закроете приложение, слот echo() никогда не будет запущен, но оператор отладки от деструктора действительно отображается в консоли:

qml: that object
destructor called

Если вы вызываете gc() в область действия функции, это не работает, возможно, потому, что объект все еще ссылается на него:

function test() {
 var test = Test.getObject()
 console.log(test.objectName)
 gc() // doesn't do anything
}

Однако, если вы сделаете это так:

function test2() {
 test()
 gc()
}

Это работает, потому что сбор мусора запускается после того, как ссылка на объект выпала из области видимости:

qml: that object
destructor called
it got destroyed

Похоже, что когда приложение существует, оно не обрабатывает сигнал destroyed(), поэтому слот echo() никогда не запускается, что, вероятно, заставляет вас ошибочно полагать, что объект протекает неуправляемым. Я не уверен, что это продукт дизайна Qt или ошибка. Объект Test создается в стеке в main(), поэтому он обязательно должен быть "жив", когда объекты, управляемые QML, уничтожаются, как и цикл цикла, который он использует, поэтому я ожидаю увидеть echo() до выхода приложения, но, похоже, это не так. Но это не вопрос вопроса, суть вопроса в том, что объекты управляются и собираются, когда они больше не ссылаются и вызывается сбор мусора.

licensed under cc by-sa 3.0 with attribution.