下载完成后带有结果的QT回调

问题描述

我有一个 QT 应用程序,其中几个不同的子组件需要从 Internet 获取数据。我想要一个 Network 类来完成所有的网络交互,然后以某种方式通知调用者。我不知道如何用插槽来做到这一点,所以我编写了一个回调解决方案:

void  Network::downloadFile(QString& urlstr,const std::function<void (QString,QByteArray,QNetworkReply::NetworkError)>& callback) {
    auto processDownload = [&]() {
        QNetworkReply * reply = qobject_cast<QNetworkReply *>(sender());
        QByteArray result;
        QString filename = reply->url().fileName();
        if (reply->error() == QNetworkReply::NoError) { // Success
            result = reply->readAll();
         }
        callback(filename,result,reply->error());
        reply->deleteLater();
    };

    QNetworkReply *reply = nam_->get(qnetworkrequest(QUrl(urlstr)));
    connect(reply,&QNetworkReply::downloadProgress,this,&Network::downloadProgress);
    connect(reply,&QNetworkReply::finished,processDownload);
}

但是,一旦调用 callback,我就会收到段错误。我尝试了几种不同的方法来定义回调,即使它为空,它仍然会崩溃(主要是段错误,有时是错误函数调用)。定义为:

std::function<void(QJsonObject,QNetworkReply::NetworkError)> f = std::bind(&MainWindow::onResult,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3);

我采取了类似 static_cast<parent_class*>(this->parent())->onResult(..)方法,但这并不是很好的解耦。我如何以一种可以传递(或向其发出信号)任何通用 std::function 的方式执行此操作?

编辑:下载文件通常这样调用

void MainWindow::DoNetworkRQ(QString url) {
    std::function<void(QJsonObject,std::placeholders::_3);
    network_.downloadFile(url,f);
}

这会导致段错误。我如何以 QT 方式执行此操作?

解决方法

@chehrlic 是对的,您正在创建一个在调用之前超出范围的回调函数。您的问题不需要以“Qt 方式”解决。但是信号和槽会起作用,所以我会告诉你怎么做。

首先,将您的信号连接到您的插槽:

void MainWindow::DoNetworkRQ(QString url) {
    connect(&network_,&Network::someSignal,this,&MainWindow::onResult);
    network_.downloadFile(url,f);
}

然后,当您的网络任务完成时发出信号:

void  Network::downloadFile(QString& urlstr,const std::function<void (QString,QByteArray,QNetworkReply::NetworkError)>& callback) {
    auto processDownload = [&]() {
        QNetworkReply * reply = qobject_cast<QNetworkReply *>(sender());
        QByteArray result;
        QString filename = reply->url().fileName();
        if (reply->error() == QNetworkReply::NoError) { // Success
            result = reply->readAll();
         }
        emit someSignal(filename,result,reply->error());
        reply->deleteLater();
    };

    QNetworkReply *reply = nam_->get(QNetworkRequest(QUrl(urlstr)));
    connect(reply,&QNetworkReply::downloadProgress,&Network::downloadProgress);
    connect(reply,&QNetworkReply::finished,processDownload);
}