Fix async crashes like getting display name from Ui.

This commit is contained in:
Julien Wadel 2025-01-20 10:36:27 +01:00
parent 5e3a2d07aa
commit 05b7251797
3 changed files with 34 additions and 17 deletions

View file

@ -36,6 +36,7 @@ public:
QVariant getValue() const;
void onSetValue(QVariant value);
void setDefaultValue(QVariant value); // Don't send signal
bool mDeleted = false;
signals:
void requestValue();
void setValue(QVariant value);

View file

@ -40,24 +40,35 @@ VariantObject::VariantObject(QString name, QVariant defaultValue, QObject *paren
mConnection = QSharedPointer<SafeConnection<SafeObject, SafeObject>>(
new SafeConnection<SafeObject, SafeObject>(mCoreObject, mModelObject), &QObject::deleteLater);
mConnection->makeConnectToCore(&SafeObject::setValue, [this, d = mName](QVariant value) {
mConnection->invokeToModel([this, value, d]() {
if (mModelObject) mModelObject->onSetValue(value);
});
});
mConnection->makeConnectToModel(&SafeObject::setValue, [this, d = mName, coreObject = mCoreObject](QVariant value) {
// Note: do not use member because 'this' is managed by GUI and can be deleted.
mConnection->invokeToCore([this, d, coreObject, value]() {
if (coreObject) coreObject->onSetValue(value);
});
});
mConnection->makeConnectToModel(&SafeObject::valueChanged, [this](QVariant value) {
mConnection->invokeToCore([this, value]() { mCoreObject->valueChanged(value); });
// Note: do not use member because 'this' is managed by GUI and can be deleted. Objects scope should have the same
// as connections so it should be fine to use the object directly.
mConnection->makeConnectToCore(&SafeObject::setValue,
[this, d = mName, modelObject = mModelObject.get()](QVariant value) {
if (modelObject && !modelObject->mDeleted)
mConnection->invokeToModel([this, value, d, modelObject]() {
if (modelObject && !modelObject->mDeleted)
modelObject->onSetValue(value);
});
});
mConnection->makeConnectToModel(&SafeObject::setValue,
[this, d = mName, coreObject = mCoreObject.get()](QVariant value) {
if (coreObject && !coreObject->mDeleted)
mConnection->invokeToCore([this, d, coreObject, value]() {
if (coreObject && !coreObject->mDeleted) coreObject->onSetValue(value);
});
});
mConnection->makeConnectToModel(&SafeObject::valueChanged, [this, coreObject = mCoreObject.get()](QVariant value) {
if (coreObject && !coreObject->mDeleted)
mConnection->invokeToCore([this, value, coreObject]() {
if (coreObject && !coreObject->mDeleted) coreObject->valueChanged(value);
});
});
connect(mCoreObject.get(), &SafeObject::valueChanged, this, &VariantObject::valueChanged);
}
VariantObject::~VariantObject() {
mCoreObject->mDeleted = true;
mModelObject->mDeleted = true;
}
QVariant VariantObject::getValue() const {

View file

@ -38,13 +38,18 @@ class VariantObject : public QObject, public AbstractObject {
public:
VariantObject(QString name, QObject *parent = nullptr);
VariantObject(QString name, QVariant defaultValue, QObject *parent = nullptr);
~VariantObject();
virtual ~VariantObject();
// Note: do not use member because 'this' is managed by GUI and can be deleted. Objects scope should have the same
// as connections so it should be fine to use the object directly.
template <typename Func, typename... Args>
void makeRequest(Func &&callable, Args &&...args) {
mConnection->makeConnectToCore(&SafeObject::requestValue, [this, callable, args...]() {
mConnection->invokeToModel([this, callable, args...]() { mModelObject->setValue(callable(args...)); });
});
mConnection->makeConnectToCore(&SafeObject::requestValue,
[this, modelObject = mModelObject.get(), callable, args...]() {
mConnection->invokeToModel([this, modelObject, callable, args...]() {
modelObject->setValue(callable(args...));
});
});
}
template <typename Sender, typename SenderClass>
void makeUpdate(Sender sender, SenderClass signal) {