【问题标题】:How to have one instance of QNetworkAccessManager?如何拥有一个 QNetworkAccessManager 实例?
【发布时间】:2018-11-14 09:53:21
【问题描述】:

有一个类似的question,但我没有发现它对我的问题有用。

在 Qt documentation 中,他们说:

一个 QNetworkAccessManager 实例应该足以满足整个 Qt 应用程序的需求。

在我的应用程序中,我在多个地方使用了QNetworkAccessManager(它们可能同时被调用),并且每次我在堆栈上创建新实例时。在阅读了那句话之后,我将我的代码更改为一个静态的QNetworkAccessManager 并在任何地方使用它。将其更改为静态成员后,我总是收到警告:

QObject::connect: Cannot connect (null)::aboutToQuit() to QNativeWifiEngine::closeHandle()

在这两种情况下,代码都可以正常工作,但是,该文档让我有点困惑。由于该产品将要商业化,我正在认真对待这个问题。我应该遵循文档还是避免警告?或者你有什么其他的建议吗?

如果不同线程上的对象需要使用QNetworkAccessManager 怎么办?


编辑:添加代码

单例设置类:

class ConnectionSettingsSingleton
{
   ...
   // constructors = default
   // copy constructor = delete

   public:
      static QNetworkAccessManager networkAccessManager;
}

我在不同的地方使用networkAccessManager,但方式相同:

QNetworkReply* HttpClient::makeRequest()
{
   switch (this->method) {
   case RequestMethod::GET:
      return ConnectionSettingsSingleton::networkAccessManager.get(this->serverRequest);
   case RequestMethod::POST:
      return ConnectionSettingsSingleton::networkAccessManager.post(this->serverRequest, QJsonDocument(this->data).toJson());
   case RequestMethod::DELETE:
      return ConnectionSettingsSingleton::networkAccessManager.deleteResource(this->serverRequest);
   default:
      return nullptr;
   }
}


编辑-2

我很友好地使用Kuba Ober's answer,有一次我收到了这个警告:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x26f6d0), parent's thread is QThread(0x2b73b8), current thread is QThread(0xa4f20a8)

原因:我试图从不同的线程访问QNAM。因此,我更新了我的问题。

【问题讨论】:

标签: c++ qt oop c++11 design-patterns


【解决方案1】:

您可以随意使用整个 Qt。不要为此使用静态变量——你无法控制它们的生命周期,而且生命周期几乎总是错误的。当QCoreApplication 不存在时,QNetworkManager 不应该存在。该警告根本不是良性的 - 它表明一个基本的设计问题。 需要控制经理的生命周期,并确保它不会超过QApplication。管理此类全局应用程序绑定对象的规范方法是将它们作为自动变量保存在main 中,并使用辅助函数来访问它们。 QPointer 自动跟踪对象的生命周期,因此永远不会悬空。因此:

main.h - 接口

QNetworkAccessManager *nMgr();

main.cpp - 实现

// This pointer is local to the translation unit, and is an
// implementation detail. It's not used anywhere else.
static QPointer<QNetworkAccessManager> globalManager;

// The global accessor method
QNetworkAccessManager *nMgr() {
  Q_ASSERT(!qApp || QThread::currentThread() == qApp->thread());
  return globalManager;
}

int main(int argc, char *argv[]) {
  QApplication app(argc, argv);
  QNetworkAccessManager mgr;
  globalManager = &mgr;
  ...
}

【讨论】:

  • 太好了,这就是我要找的。谢谢!
  • 我更新了我的问题。您能否详细说明您的答案!?
  • @Bobur 不,您在已经回答的问题中添加了一个不相关的问题。您现在遇到的问题是其他问题,需要在其他地方回答。无论如何,除了创建它的线程之外,您不能从任何线程访问 QNAM,因为它的方法没有记录为线程安全。 QNAM 在任何方面都不是特别的:如果 QObject 方法没有记录为线程安全 - 它不是。 QNAM 就像一个由 Qt 管理的网络访问管理器系统的句柄。如果您需要在其他线程中使用它,请在那里创建实例。
  • 感谢您的友好回答!这是我唯一想到的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-07
  • 1970-01-01
  • 2012-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多