Qt 远程对象副本¶
描述了副本的概念以及它如何作为代理对象工作。.. _replica: 一个QRemoteObjectReplica(“副本”)是一个代理对象,它拥有与它复制的Source QObject大致相同的API。此外,还有一些属性和信号,使得可以检测到副本何时初始化或是否失去了与源对象的连接。还有一些其他差异,特别是源对象上的常量属性在副本上不能是常量。在副本实例化时,该值将未知;只有在副本初始化后才会知道。有关更多信息,请参阅远程对象交互。
编译的副本是一个基于QRemoteObjectReplica的类型,其中派生类定义由repc编译器自动生成。当您使用CMake函数或qmake变量来运行repc编译器时,这会使生成成为构建过程的一部分。虽然只生成了一个头文件,但它是一个完整的类型。没有公共构造函数,因此您需要使用acquire模板函数来创建Replica实例。
一个QRemoteObjectDynamicReplica可以在运行时生成。为此,您需要调用acquireDynamic(),并传入源名称(一个QString)作为参数。动态副本在C++中使用时稍微冗长一些,但它们不需要编译。动态副本在初始化之前不支持初始属性值或内省。
这两种创建副本的方式之间的一个重要区别在于副本初始化之前的行为。由于动态副本仅在初始化后获得一个metaObject,因此在初始化之前它基本上没有API——没有属性,也没有信号可以连接到插槽。
因为编译副本的metaObjects是在编译时创建的,所以当副本实例化时,它们的API是可用的。你甚至可以在模板文件中为属性提供默认值,这些默认值在副本用源中的当前值初始化之前会被使用。
副本初始化¶
一个主机节点将与连接到它的每个其他节点共享它所承载的源列表。当源被添加到列表中或从列表中移除时,此主机会发送更新。通过这种方式,连接的节点将始终知道它可以附加到哪些源。对特定源的更改仅传播到具有该源副本的节点。因此,这避免了任何不必要的网络流量。
当一个节点获取到一个已知源的副本时,它会向主机节点发送该源的请求。主机节点在收到此请求后,会创建一个包含该源所有属性当前值的回复包。如果请求的副本是dynamic,则回复包中会包含该源的API定义。从那时起,副本的节点将被包含在接收该源更改的连接列表中。
如果实例化了一个副本,但其节点未连接到托管请求源的节点——或者该对象存在于主机节点进程中,但未为QObject启用共享/远程处理——副本仍将被创建,但保持未初始化状态。
如果稍后,副本的节点收到通知,请求的源可以从连接的节点获得,那么它将请求该源并开始初始化过程。
如果与主机节点的连接丢失,副本将转换为无效状态。它将尝试重新连接,并在连接恢复时重新初始化;这确保所有属性都是最新的。
副本所有权¶
acquire 方法返回一个指向由节点实例化的副本 QObject 的指针。节点无法知道副本的预期生命周期。因此,当不再需要副本时,调用程序有责任删除它。
你可以实例化同一副本的多个副本。来自单个节点的同一源的所有副本将共享一个处理网络通信的私有数据成员。这意味着副本的多个实例不会引入额外的网络流量,尽管会有一些额外的处理开销。未能删除副本将阻止此私有对象的引用计数达到0,并在调用进程退出之前导致不必要的网络通信。因此,建议使用QScopedPointer或QSharedPointer来帮助跟踪副本的生命周期。