10

Daemons and Services Programming Guides告诉我们可以通过打开的 XPC 连接返回代理对象,甚至作为回复块参数。

通过代理传递对象

大多数时候,复制对象并将它们发送到连接的另一端是有意义的。然而,这并不总是可取的。尤其:

如果您需要在客户端应用程序和助手之间共享数据的单个实例,则必须通过代理传递对象。如果一个对象需要调用应用程序中其他对象上的方法,而这些方法您不能或不希望通过连接传递(例如用户界面对象),那么您必须通过代理传递一个对象——调用者、被调用者(其中可能),或者您专门为此目的构建的中继对象。通过代理传递对象的缺点是性能显着降低(因为对对象的每次访问都需要进程间通信)。因此,如果无法通过复制传递对象,则应仅通过代理传递对象。

您可以配置其他代理对象,类似于配置初始连接的 remoteObjectInterface 属性的方式。首先,确定应该由代理传递方法的哪个参数,然后指定一个 NSXPCInterface 对象,该对象定义该对象的接口。

第一个问题来了:代理传递的对象应该如何定义?作为符合 NSXPCProxyCreating 协议的对象?那么是否应该实现 remoteObjectProxy 和 remoteObjectProxyWithErrorHandler: 方法?

下面是一个例子,这对我来说根本不清楚。特别是我不明白我应该在哪里调用 NSXPCInterface 方法 (setInterface:forSelector:argumentIndex:ofReply:) 将参数作为代理列入白名单:在 XPC 服务代码或主机中?

方法的第一个参数是参数 0,然后是参数 1,依此类推。

在这种情况下,为 ofReply 参数传递值 NO,因为此代码正在修改方法本身的参数之一的白名单。如果您将方法的回复块的参数的类列入白名单,请改为传递 YES。

所以问题是:任何人都可以为我提供一个关于如何在 XPC 方法调用的块回复中将对象作为代理返回的清晰教程吗?

4

1 回答 1

15

我现在可以回答我自己的问题:要在 XPC 方法调用的块回复中返回一个对象作为代理,应该同时调用 setInterface:forSelector:argumentIndex:ofReply: 方法:

  • 在 XPC 服务的端点中,其中exportedInterface声明了
  • 在主机中,remoteObjectInterface声明了

即,通用代码:

// common (service/host) protocol definition
@protocol Service
@end

@protocol ServiceFactory
-(void)connectToNewService: (void (^)(id<Service>)reply;
@end

在 XPC 服务中:

// Implement the one method in the NSXPCListenerDelegate protocol.
-(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection*)newConnection {   

    NSXPCInterface *serviceFactoryInterface =[NSXPCInterface interfaceWithProtocol:@protocol(ServiceFactory)];
    NSXPCInterface *serviceInterface =[NSXPCInterface interfaceWithProtocol:@protocol(Service)];

    // connection has to be returned as proxy, not as a copy
    [serviceFactoryInterface setInterface: serviceInterface
                          forSelector: @selector(connectToNewService:)
                        argumentIndex: 0
                              ofReply: YES];

    newConnection.exportedInterface = serviceFactoryInterface;
    newConnection.exportedObject = self;

    [newConnection resume];
    return YES;

}

在主机代码中:

// in the host

- (void)openNewService
{
    NSXPCConnection *xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"eu.mycompany.servicefactory"];
    NSXPCInterface *serviceFactoryInterface =[NSXPCInterface interfaceWithProtocol:@protocol(ServiceFactory)];
    NSXPCInterface *serviceInterface =[NSXPCInterface interfaceWithProtocol:@protocol(Service)];

    // connection has to be returned as proxy, not as a copy
    [serviceFactoryInterface setInterface: serviceInterface
                          forSelector: @selector(connectToNewService:)
                        argumentIndex: 0
                          ofReply: YES];

    xpcConnection.remoteObjectInterface = serviceFactoryInterface;
    [xpcConnection resume];

    [[xpcConnection remoteObjectProxy] connectToNewService:^(id<Service> newService) {

        // here a newService is returned as NSXPCDistantObject <Service>*
        [xpcConnection invalidate];

    }];

}
于 2013-02-02T16:03:43.050 回答