2015-01-16 122 views
2

我試圖測試QML以瞭解它如何與C++一起工作。我有ClassAClassB - 2個類似的C++類。這是一個ClassA。所有的方法都是用自己的名字來解釋,所以我不會在這裏放置實現。QML內存管理

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中重現這種情況併發布報告。

+0

你可以把'ClassA'放入一個'Component'中,然後通過'var ca = thisComponent.createObject(parent)'創建它。至於對象破壞 - 你能確定在哪個步驟調用了desctructor?正如我所知道的,如果沒有引用它,那麼你就不得不以這種方式尋找對象。 – folibis

+0

@folibis在調試模式下,這個問題成爲一個概率問題。有時它發生了,有時並沒有發生。跟蹤沒有給我太多的信息。如預期的那樣,所有函數調用都在共享庫中完成,其中一些已隱藏。而且它們都具有通常的名稱,用於試圖刪除和反對的功能。無論如何,讀一個補充發布,並感謝您的建議如何不需要創建* .qml文件。 – JustAnotherCurious

回答

2
  1. 像任何QML類型,你可以在另一靜態定義組件:

    Component { 
        id: classAComponent 
        ClassA { } 
    } 
    onClicked { 
        var ca = classAComponent.createObject() 
    } 
    
  2. 這裏有一個細微之處:分配QML對象到QML property將增加它的JavaScript REF-數。但是在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() 
    } 
    

    理想的情況下,你應該動態地避免創建對象儘可能和使用C++對象靜態像正常QML部件並讓陳述性結構保持Q自動物體骨幹,像這樣:

    ClassA { 
        classB: ClassB { } 
    } 
    
  3. 可悲的是沒有這麼多,我知道的最好的,更多的QML比C++是Dynamic QML Object Creation from JavaScript

+0

1)謝謝。這種方式比我更好。 2)我另外寫道,在Qt的新版本中,這種情況並不像我描述的那樣。在調試中,它在prev中是隨機的。版。而且,如果有人創建了一個對象,他不應該關心如何描述組件(QML或QObject)。我希望這是一個錯誤,現在它已經修復並希望「但是隻存儲在C++對象的Q_PROPERTY中的實例不會被垃圾收集器標記」現在不成立。 =) – JustAnotherCurious