QML 内存管理



我正在尝试测试QML以了解它如何与C++一起工作。我有ClassAClassB - 2 个类似的C++类。这是一个ClassA.所有方法的名称都是不言自明的,所以我不会在这里放置实现。

class ClassB;
class ClassA : public QObject
{
    Q_OBJECT
public:
    explicit ClassA(QObject *parent = 0);
    ~ClassA();
    Q_PROPERTY(ClassB* classB READ getClassB WRITE setClassB NOTIFY classBChanged)
    ClassB* getClassB() const;
    void setClassB(ClassB *classB);
signals:
    void classBChanged();
private:
    ClassB *m_classB;
};

ClassB是一样的,只需将所有*lassA*更改为*lassB*,将所有*lassB*更改为*lassA*即可。

然后我注册了 QML 中分类的两者

qmlRegisterType<ClassA>("testmodule.test",1,0,"ClassA");
qmlRegisterType<ClassB>("testmodule.test",1,0,"ClassB");

在鼠标单击QML代码中,我像这样创建两个对象:

onClicked: {
    var comp = Qt.createComponent("TClassA.qml"); //TClassA.qml is 
                                                  //a component of type 
                                                  //ClassA
    var ca = comp.createObject();
    comp = Qt.createComponent("TClassB.qml");
    var cb = comp.createObject();
    ca.classB = cb;
    cb.classA = ca;
    parent.blockFromGC = ca;
}

之后,我用gc()调用垃圾收集器.我预计ca被阻止通过parent.blockFromGC删除,cb被阻止从ca参考删除。但是垃圾收集器摧毁了cb,之后parent.blockFromGC.classB === null.

所以我对这段代码有第二个MouseArea

onClicked: {
    console.log(mouse.button)
//    if (mouse.button == Qt.RightButton) {
//        console.log(parent.vasya.classB)
//    }
    gc();
    console.log(parent.blockFromGC.classB) //I use cb here
}

因此,当我单击控制台MouseArea时:

qml: 1 //Left button
qml: null //value of parent.blockFromGC.classB
classB destroyed:  TQMLClassB(0x34960d0) //I have qDebug() in destructor

所以我的对象cb被摧毁了。

所以我有这个问题:

1)有没有办法将C++类型注册为基本类型,这样我就可以编写var ca = new ClassA()而不是创建*.qml文件,创建组件并最终创建对象?

2)为什么垃圾回收器破坏了我的cb对象,我该怎么办防止此对象被删除?

此外!如果我取消注释那些注释行

//    if (mouse.button == Qt.RightButton) {
//        console.log(parent.vasya.classB)
//    }

无论我按下哪个按钮,对象都不会再被破坏。

qml: 1 //left button
qml: TQMLClassB(0x3df8e90) //object is alive
.....
qml: 2 //right button
qml: TQMLClassB(0x3df8e90) //before gc() - alive
qml: TQMLClassB(0x3df8e90) //after gc() - alive

3) 在哪里可以详细了解QML内存管理?我觉得这种行为真的很奇怪。

补充1:我更多地玩了一下这种情况,结果是不可预测的。我从 5.3 更新到 Qt 5.4,这种删除对象的行为已经消失。问题是该行为是如此不可预测,以至于我无法在Qt 5.4中重现此行为的事实并不意味着问题已解决。我将尝试查看错误报告和错误修复。如果我发现了什么,我会在这里发布。如果没有,我将尝试在Qt 5.4中重现这种情况并发布报告。

  1. 与任何 QML 类型一样,您可以在另一个组件中静态定义一个组件:

    Component {
        id: classAComponent
        ClassA { }
    }
    onClicked {
        var ca = classAComponent.createObject()
    }
    
  2. 这里有一个微妙之处:将QML对象分配给QML property将增加其JavaScript引用计数。但是,存储在 C++ 对象Q_PROPERTY中的实例不会被垃圾回收器标记。

    QML实行双重所有制。首先,它定义了用于显示和所有权的 QObject/QQuickItem 的层次结构。附加到此主干的是一个垃圾收集系统,其中任何QML对象都可以通过property var拥有JavaScript对象树。

    因此,为了保持 ClassB 对象的活动状态,要么必须将其保留在 QML 属性中,要么在调用 component.createObject() 时为其提供父级(这是一个硬所有权;当父对象被销毁时,无论对它的任何 JS 引用,它都会被销毁)

    QML 属性的示例:

    Component {
        id: classAComponent
        ClassA {
            property Item refClassB
        }
    }
    onClicked {
        var ca = classAComponent.createObject()
        ca.refClassB = classBComponent.createObject()
    }
    

    理想情况下,您应该尽可能避免动态创建对象,并像普通 QML 组件一样静态地使用 C++ 对象,并让声明式结构自动维护 QObject 主干,如下所示:

    ClassA {
        classB: ClassB { }
    }
    
  3. 可悲的是,我所知道的最好的,比C++更多的是来自JavaScript的动态QML对象创建。

相关内容

  • 没有找到相关文章

最新更新