Что происходит с соединением сигнал / слот, если указатель указывает на новый объект - PullRequest
1 голос
/ 20 марта 2012

У меня есть загрузчик со следующим кодом:

if(!_canceled) {
    _reply = _accessManager.put(request, item);

    if(_reply) { 
        _currentItem = item;

        bool status = connect(_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(reportUploadProgress(qint64, qint64)));
        pantheios::log(pantheios::debug, "StorageProvider(): connection uploadProgress(qint64, qint64), status", pantheios::boolean(status));
        status = connect(_reply, SIGNAL(finished()), this, SLOT(handleFinishedRequest()));
        pantheios::log(pantheios::debug, "StorageProvider(): connection finished(), status", pantheios::boolean(status));

    } else {
        emit noReply();
        pantheios::log(pantheios::error, "StorageProvider(): no reply", item.toUtf8());
    }

Затем в готовом слоте я делаю это:

QNetworkReply *reply =  qobject_cast<QNetworkReply*>(sender());

if(reply->error() > QNetworkReply::NoError) { 
    pantheios::log(pantheios::error, "StorageProvider(handleFinishedRequest) ", reply->errorString().toUtf8());

    if((reply->error() == QNetworkReply::TemporaryNetworkFailureError) || (reply->error() == QNetworkReply::ContentReSendError)) {
                    // retry the last request
        _reply = accessManager.put(reply->request(), _currentItem);
    }

} else {
    ...
}

Этот StorageProvider сможет обрабатывать различные запросы иОтвет будет иметь разные связи в зависимости от того, в какой функции он создан.Причина, по которой ответ является переменной-членом, заключается в том, что я могу удалить его, прежде чем выполнить следующий запрос.

Итак, мой вопрос: нужно ли мне снова устанавливать соединение, если я переиздаю ответ?Слот / сигнал подключен к указателю или объекту?Кроме того, есть ли лучший способ удалить старый ответ?

Редактировать: Изменен код на этот для обработчика законченного запроса;

if(_currentReply->error() > QNetworkReply::NoError) { 
    pantheios::log(pantheios::error, "StorageProvider(handleFinishedRequest) ", _currentReply->errorString().toUtf8());

    if(((_currentReply->error() == QNetworkReply::TemporaryNetworkFailureError) || (_currentReply->error() == QNetworkReply::ContentReSendError)) && (_currentRetries < 4)) {

        QNetworkRequest lastRequest = _currentReply->request();
        _currentReply->deleteLater();

        _currentReply = _accessManager.put(lastRequest, _currentItem);

        if(_currentReply) { 

            bool status = connect(_currentReply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(reportUploadProgress(qint64, qint64)));
            pantheios::log(pantheios::debug, "StorageProvider(retry): connection uploadProgress(qint64, qint64), status", pantheios::boolean(status));
            status = connect(_currentReply, SIGNAL(finished()), this, SLOT(handleFinishedRequest()));
            pantheios::log(pantheios::debug, "StorageProvider(retry): connection finished(), status", pantheios::boolean(status));

        } else {
            emit noReply();
            pantheios::log(pantheios::error, "StorageProvider(retry): AccessManager no reply");
        }
    }

}

1 Ответ

3 голосов
/ 20 марта 2012

Сигнал связан с объектом, а не с переменной-указателем, поэтому вам нужно каждый раз устанавливать новые подключения.

И чтобы удалить ответ, просто наберите deleteLater() в начале finished() slot:

QNetworkReply *reply =  qobject_cast<QNetworkReply*>(sender());
reply->deleteLater();

, таким образом, он будет удален в конце выполнения слота.


Вы можете избежать использования sender(), оборачивая каждый запрос (начальныйодин плюс все повторы) внутри собственного QObject производного класса:
class PutRequest : public QObject {
Q_OBJECT
private:
     QNetworkAccessManager *_manager;
     QNetworkReply *_reply;
     QIODevice *_item; // Or whatever type the second parameter of put is
public:
     explicit PutRequest(QNetworkAccessManager *manager, QNetworkRequest *request, QIODevice *item, QObject *parent = 0)
       : QObject(parent), _manager, _reply(0), _item(item) 
     {            
         _reply = _manager.put(request, item);
         connectSignalsAndSlots();
     }       

private:
     void connectSignalsAndSlots() {
         // to delete the reply if the PutRequest object is destroyed
         reply_->setParent(this);
         // since the reply is encapsulated, the object has to emit its own
         // upload progress signal
         connect(_reply, SIGNAL(uploadProgress(qint64, qint64)), this, SIGNAL(uploadProgress(qint64, qint64)));
         connect(_reply, SIGNAL(finished()), this, SLOT(handleFinishedRequest()));
     }

private slots:
     void handleFinishedRequest() {
         _reply->deleteLater();
         if(reply->error() != QNetworkReply::NoError) {
               pantheios::log(pantheios::error, "StorageProvider(handleFinishedRequest) ", reply->errorString().toUtf8());

         if((_reply->error() == QNetworkReply::TemporaryNetworkFailureError) || (reply->error() == QNetworkReply::ContentReSendError)) {
            // retry the last request
            _reply = _manager.put(_reply->request(), _item);
            connectSignalsAndSlots();
         }

         } else {
         ...                 
             emit finished(this);
         }         
     }
signals:
     void uploadProgress(qint64, qint64);
     // emitted when the upload is successful (after the possible retries)
     void finished(PutRequest*);
};

И вы бы создали запрос следующим образом:

if(!_canceled) {
    PutRequest *putRequest = new PutRequest(_accessManager, request, item);

    // and you connect putRequest object signals to whatever you connected _reply to
...