한 가지 간단한 방법을.
포인터로가 아닌 값으로 네트워크 관리자와 다른 개체를 유지하십시오. 포인터는 여분의 간접 참조이므로 대부분의 경우 완전히 필요하지 않습니다. dataModel
인스턴스와 응답 사이 : 1 매핑 아래
는 완전한 C++ 11 두 Qt는 4 일 예를 들어, 5
// https://github.com/KubaO/stackoverflown/tree/master/questions/netreply-property-38775573
#include <QtNetwork>
#include <QStringListModel> // needed for Qt 4
using DataModel = QStringListModel;
const char kDataModel[] = "dataModel";
class Worker : public QObject {
Q_OBJECT
QNetworkAccessManager m_manager;
Q_SLOT void onFeedRetrieved(QNetworkReply* reply) {
auto dataModelObject = qvariant_cast<QObject*>(reply->property(kDataModel));
auto dataModel = qobject_cast<DataModel*>(dataModelObject);
qDebug() << dataModel;
emit got(reply);
}
public:
Worker(QObject * parent = nullptr) : QObject{parent} {
connect(&m_manager, SIGNAL(finished(QNetworkReply*)),
SLOT(onFeedRetrieved(QNetworkReply*)));
}
void newRequest(const QUrl & url, DataModel * dataModel) {
QNetworkRequest request{url};
auto reply = m_manager.get(request);
reply->setProperty(kDataModel, QVariant::fromValue((QObject*)dataModel));
}
Q_SIGNAL void got(QNetworkReply*);
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
DataModel model;
Worker worker;
worker.newRequest(
QUrl{"http://stackoverflow.com/questions/38775573/best-way-to-use-qsignalmapper"},
&model);
QObject::connect(&worker, SIGNAL(got(QNetworkReply*)), &app, SLOT(quit()));
return app.exec();
}
#include "main.moc"
1가있을 경우에만 QSignalMapper
을 사용할 수 있습니다. 하나의 데이터 모델이 여러 응답에 사용되면 작동하지 않습니다.
그런 다음 속성 시스템을 사용하여, 할당 횟수에 대해 정말 관심이 있다면 조금 더 많은 오버 헤드를 가지고 : 개체의 첫 번째 속성을 설정하면 두 개 이상의 할당을 수행 - 내부 클래스 및 QMap
에 대한 데이터 세그먼트를. 그래서 2N 배정입니다. 이에 비해 매핑을 QSignalMapper
에 추가하면 상각 된 로그 (N) 할당이 수행됩니다. 그렇지 않으면 QSignalMapper
은 쓸모가 없습니다.
Qt 5를 사용하면 std::bind
또는 람다에 연결할 수 있기 때문에 완전히 반 패턴이됩니다. 어쨌든 QSignalMapper
이 QVariant
에 매핑 된 경우 훨씬 더 좋을 것입니다.
첫 번째 연결을 개체에 추가하면 (다른) 내부 클래스도 할당됩니다. 이러한 잠재적 비용을 피하려면 자주 작성한 오브젝트에 연결을 추가하지 않아야합니다. QNetworkReply::finished()
에 연결하는 대신 번을 번에 연결하고 QNetworkManager::finished(QNetworkReply*)
신호를 연결하는 것이 좋습니다. 아아,이 절약은 대기열에있는 연결을 사용하면 사라집니다. 즉, 현재 슬롯에 전달 된 모든 인수에 대해 추가 할당 비용이 발생합니다. 이것은 현재의 구현의 단점 일 뿐이며 아키텍처상의 한계는 아닙니다. 이후의 사소한 Qt 릴리즈에서 제거 될 수 있습니다 (나 자신이나 다른 누군가가 그것에 도달하면).
#include <QtNetwork>
#include <QStringListModel> // needed for Qt 4
using DataModel = QStringListModel;
class Worker : public QObject {
Q_OBJECT
QNetworkAccessManager m_manager;
QSignalMapper m_mapper;
// QObject::connect is not clever enough to know that QNetworkReply* is-a QObject*
Q_SLOT void map(QNetworkReply* reply) { m_mapper.map(reply); }
Q_SLOT void onFeedRetrieved(QObject * dataModelObject) {
auto dataModel = qobject_cast<DataModel*>(dataModelObject);
auto reply = qobject_cast<QNetworkReply*>(m_mapper.mapping(dataModelObject));
qDebug() << dataModel << reply;
emit got(reply);
}
public:
Worker(QObject * parent = nullptr) : QObject{parent} {
connect(&m_manager, SIGNAL(finished(QNetworkReply*)), SLOT(map(QNetworkReply*)));
connect(&m_mapper, SIGNAL(mapped(QObject*)), SLOT(onFeedRetrieved(QObject*)));
}
void newRequest(const QUrl & url, DataModel * dataModel) {
QNetworkRequest request{url};
auto reply = m_manager.get(request);
// Ensure a unique mapping
Q_ASSERT(m_mapper.mapping(dataModel) == nullptr);
m_mapper.setMapping(reply, dataModel);
}
Q_SIGNAL void got(QNetworkReply*);
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
DataModel model;
Worker worker;
QObject::connect(&worker, SIGNAL(got(QNetworkReply*)), &app, SLOT(quit()));
worker.newRequest(
QUrl{"http://stackoverflow.com/questions/38775573/best-way-to-use-qsignalmapper"},
&model);
return app.exec();
}
#include "main.moc"
어떤 QNetworkReply가 슬롯을 호출했는지 확인할 수 있습니까? QObject :: setProperty를 사용해야합니까? –
'QMap' 또는'QHash'에 활성 응답에 대한 포인터를 저장할 수 있고'QSignalMapper'처럼 키로 검색 할 수 있습니다. 또는 회신에 개체 이름을 설정하고이를 확인할 수 있습니다. –