Don't leak components in QQuickLoader

Only create source component in loadFromSource if it does not already exist.
Previously toggling the active status when loading from source would create
a new source component every time active became true.

[ChangeLog][QtQuick][Loader] Don't leak components when changing source url.

Change-Id: I1e4cfd5613e3851fcb4f3f55e78981f7c070cc77
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Colin Ogilvie 2017-06-02 11:35:07 +01:00 committed by Shawn Rutledge
parent df8d59e4b4
commit d6a5e14cdd
2 changed files with 59 additions and 2 deletions

View File

@ -112,6 +112,8 @@ void QQuickLoaderPrivate::clear()
q, SIGNAL(progressChanged()));
component->deleteLater();
component = nullptr;
} else if (component) {
component = nullptr;
}
componentStrongReference.clear();
source = QUrl();
@ -438,6 +440,7 @@ void QQuickLoader::loadFromSource()
if (isComponentComplete()) {
QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
if (!d->component)
d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
d->load();
}
@ -828,6 +831,7 @@ void QQuickLoader::componentComplete()
if (active()) {
if (d->loadingFromSource) {
QQmlComponent::CompilationMode mode = d->asynchronous ? QQmlComponent::Asynchronous : QQmlComponent::PreferSynchronous;
if (!d->component)
d->component = new QQmlComponent(qmlEngine(this), d->source, mode, this);
}
d->load();

View File

@ -126,6 +126,8 @@ private slots:
void parentErrors();
void rootContext();
void sourceURLKeepComponent();
};
Q_DECLARE_METATYPE(QList<QQmlError>)
@ -1388,6 +1390,57 @@ void tst_QQuickLoader::rootContext()
QCOMPARE(objectInRootContext.didIt, 2);
}
void tst_QQuickLoader::sourceURLKeepComponent()
{
QQmlEngine engine;
QQmlComponent component(&engine);
component.setData(QByteArray(
"import QtQuick 2.0\n"
" Loader { id: loader\n }"),
dataDirectoryUrl());
QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create()));
loader->setSource(testFileUrl("/Rect120x60.qml"));
QVERIFY(loader);
QVERIFY(loader->item());
QVERIFY(loader->sourceComponent());
QCOMPARE(loader->progress(), 1.0);
const QPointer<QQmlComponent> sourceComponent = loader->sourceComponent();
//Ensure toggling active status does not recreate component
loader->setActive(false);
QVERIFY(!loader->item());
QVERIFY(loader->sourceComponent());
QCOMPARE(sourceComponent.data(), loader->sourceComponent());
loader->setActive(true);
QVERIFY(loader->item());
QVERIFY(loader->sourceComponent());
QCOMPARE(sourceComponent.data(), loader->sourceComponent());
loader->setActive(false);
QVERIFY(!loader->item());
QVERIFY(loader->sourceComponent());
QCOMPARE(sourceComponent.data(), loader->sourceComponent());
//Ensure changing source url causes component to be recreated when inactive
loader->setSource(testFileUrl("/BlueRect.qml"));
loader->setActive(true);
QVERIFY(loader->item());
QVERIFY(loader->sourceComponent());
const QPointer<QQmlComponent> newSourceComponent = loader->sourceComponent();
QVERIFY(sourceComponent.data() != newSourceComponent.data());
//Ensure changing source url causes component to be recreated when active
loader->setSource(testFileUrl("/Rect120x60.qml"));
QVERIFY(loader->sourceComponent() != newSourceComponent.data());
}
QTEST_MAIN(tst_QQuickLoader)
#include "tst_qquickloader.moc"