[英]Why is QML deleting my C++ ListView model?
我正在iOS 9
上使用Qt 5.5.1
嘗試將動態創建的QAbstractListModel
分配給ListView
的model
屬性:
Window {
ListView {
model: api.model()
delegate: delegate
}
Component {
id: delegate
Text { text: "Test" }
}
}
api
是使用setContextProperty
分配給QML
上下文的C++
對象。 model
方法是Q_INVOKABLE
,它返回QAbstractListModel *
。 所有這些都有效,我的ListView
充滿了數據。
問題是當我開始滾動時。 通常在第二次完整滾動(到底部,再回到頂部並再次向下)之后,我的ListView
開始清除。 調試器告訴我QAbstractListModel
被銷毀。
我不想在模型上設置CppOwnership
。 還有另一種方法可以防止ListView
破壞其模型嗎?
QML在這方面似乎有點破損,我經歷了在多種情況下仍在使用的對象的完全任意刪除。 帶有父對象並被JS引擎引用的對象沒有明顯原因被刪除,而JS垃圾仍然占用數百兆的內存而不是被釋放。 這適用於從C ++返回的對象和在QML中創建的對象。 當對象從C ++函數返回到QML時,所有權將傳遞給QML引擎,這使對象容易受到此類任意刪除的攻擊。
解決方案是強制CPP所有權並手動管理對象的生存期-請記住destroy()
在此類對象上不起作用,因此您必須使用QML中的C ++函數將其刪除。
qmlEngine.setObjectOwnership(obj, QQmlEngine::CppOwnership);
另外,正如BaCaRoZzo所述,將模型作為屬性公開給api可能是合適的形式。 它取決於函數是僅僅是現有對象的訪問器,還是它自己創建對象。
無論如何,請記住,此時不能也不應該信任QML對象生存期管理。
即使我接受了ddriver
的回答,我ddriver
找到了一個似乎更符合我想要的解決方案。
通過動態加載組件並將模型存儲為變量,我可以獲得QML
使我的C++
模型保持活動狀態並在需要時銷毀它們,例如:
MyComponent {
property var model: api.createModel()
ListView {
model: model
delegate: delegate
[...]
}
Component { id: delegate [...] }
Component.onDestruction: model.destroy()
}
不幸的是,似乎需要對model.destroy()
調用。 我原本希望垃圾收集器來處理此問題,但事實並非如此。
到目前為止,我只測試了這是玩具示例,請注意。
只能說-我可以在Linux x86_64和Android ARMv7上確認相同的問題。
MyComponent {
property var model: api.createModel()
ListView {
model: model
delegate: delegate
[...]
}
Component { id: delegate [...] }
}
如果您不介意稍后銷毀模型,似乎就足夠了。
我想在ddriver的答案中添加一些內容,這不僅僅是評論。
我也遇到了同樣的問題。 基本上,我想創建一個動態列表視圖模型(實際上是QAbstractListModel)。 通常的方法是像這樣將模型放在主要(或某個地方)的前面:
QQmlContext* ctxt = engine.rootContext();
ctxt->setContextProperty("myModel", &model);
在這種情況下, 每個對象只有一個模型,因此我需要一個動態解決方案。
我有一個QObject
可以為列表創建模型。 創建的模型源自QAbstractListModel
。 我的QObject
主機使用Q_INVOKABLE
創建並給出了模型。
第一個問題是這樣生成的模型的類型未知,必須注冊。 通常的qmlRegisterType
不起作用,因為無法復制QAbstractListModels。 因此,您必須使用qmlRegisterUncreatableType
注冊。
那是第一位。 現在該模型有效, 但誰將其銷毀?
事實證明,由於所有權是作為Q_INVOKABLE
訪問器的一部分隱式賦予QML的,因此我的C ++代碼和 QML都試圖破壞對象。
但是僅僅讓QML清理是不好的。 我跟蹤了什么時候發生,而根本沒有及時發生。 基本上,除非我做一些相當大的事情,例如調整窗口大小,否則它不會清理。 大概最終會清理掉(垃圾等),但是我真的希望這些動態模型在其宿主QObject
出現故障時被清理掉。
ddriver的想法就是這樣。 但也要記得向qmlRegisterUncreatableType
注冊。
例如,
inline MyModel* MyHostObject::getModel()
{
if (!_model)
{
_model = new MyModel(this);
// retain ownership of this object.
QQmlEngine::setObjectOwnership(_model, QQmlEngine::CppOwnership);
}
return _model;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.