我处于高度动态的环境中,大量使用来自源的组件的动态实例化。当然,我担心每次动态创建对象时必须解析这些源的开销。当情况允许时,我使用手动缓存:
readonly property var componentCache: new Object
function create(type) {
var comp = componentCache[type]
if (comp === undefined) { // "cache miss"
comp = Qt.createComponent(type)
if (comp.status !== Component.Ready) {
console.log("Component creation failed: " + comp.errorString())
return null
} else {
componentCache[type] = comp
}
}
return comp.createObject()
}
除了这并不总是适用之外,例如,使用Loader
和一个需要使用setSource(source, properties)
函数指定对象属性的组件。在这种情况下,无法使用手动缓存的Component
,因为该函数只接受网址。文档模糊地提到"缓存"但是,对于来自该源的组件,该缓存是否是QML引擎范围还是更加可能 - 不仅仅是针对该特定Loader
。
如果此函数的活动属性为false 调用时,不会加载给定的源组件而是源 和初始属性将被缓存。当装载机处于活动状态时, 将使用initial创建源组件的实例 属性集。
问题是如何处理这个问题,甚至是必要的?也许Qt默认从源缓存中做组件?在避免冗余源加载(来自磁盘或更糟糕的网络),解析和组件准备方面,缓存肯定是有意义的,但是它的效果只会在过度动态实例化的情况下突出,而且#34;典型的" ; QML动态对象创建场景通常涉及一次性对象,在这种情况下,缓存将是无用的内存开销。在源可能在实例化之间发生变化的情况下,缓存也没有意义。
因为我没有时间去挖掘Qt API背后的私有实现,如果我不得不猜测,我说来源缓存的组件不太可能,但是仅仅是猜测,它可能也是错误的。
答案 0 :(得分:1)
本身不是答案,我昨天闯入了组件缓存的问题 - 并且惊讶地发现Qt似乎缓存了组件。至少在创建动态组件时,与createComponent
相关的日志语句仅在我的测试应用中出现一次。我已经四处搜索过,并且没有看到有关缓存的文档中的任何具体信息。我确实在QQMLEngine Class
中遇到了几个有趣的方法。然后我遇到了release notes for Qt 5.4
Qt.createComponent()返回的组件不再是父级 到发动机。请务必持有参考或提供父母。
所以?如果提供了父级,则缓存(?)似乎是这种情况。 (并且对于5.5+?)如果您想自己管理它,请不要提供父母并保留参考。 (?)
QQmlEngine :: clearComponentCache()
清除引擎&#39> 内部组件缓存。
此函数导致该属性 先前由引擎加载的所有组件的元数据 销毁。所有先前加载的组件和属性绑定 对于从这些组件创建的所有现存对象将停止 function。
此函数将引擎返回到它的状态 不包含任何已加载的组件数据。这可能有用 为了重新加载前一个组件集的较小子集,或者 加载以前加载的组件的新版本。
一旦 组件缓存已被清除,组件必须先加载 可以创建新对象。
void QQmlEngine :: trimComponentCache()
修剪引擎的内部组件缓存。
此函数会导致任何已加载组件的属性元数据 这些目前尚未被销毁。
如果存在任何组件,则认为该组件正在使用中 组件本身的实例,其他组件的任何实例 使用组件或任何实例化的对象 组件。
答案 1 :(得分:0)
在玩了一些代码之后,看起来缓存也发生在"有问题的情况下" Loader.setSource()
。
从this question运行示例代码,我发现由于Qt的硬编码限制,常规组件创建无法扩展超过10个节点的树:
// Do not create infinite recursion in object creation
static const int maxCreationDepth = 10;
如果常规方案中存在多个嵌套的10个组件实例,产品不正确的树并生成警告,则会导致组件实例化中止。
使用setSource()
时不会发生这种情况,显而易见的原因是组件被缓存,因此不会发生组件实例化。