11

我在 10.8 上的一个应用程序中使用 XPC。它具有为导出接口和远程接口定义的协议的标准设置。我遇到的问题是我在导出接口上的一种方法。

我有一个模型类,我们就叫它吧Foo。此类符合NSSecureCoding、实现+supportsSecureCoding和使用安全编码方法正确编码/解码内部属性。当通过我的导出接口上的仅涉及单个实例的方法传递此对象时,它可以正常工作。

当我想传递这些对象的集合或对象时,就会出现NSArray问题Foo。这是导出界面上签名的示例:

- (void)grabSomethingWithCompletion:(void (^)(NSArray *foos))completion;

Foo如文档中所述,我已将课程列入白名单:

NSSet *classes = [NSSet setWithObject:Foo.class];
[exportedInterface setClasses:classes forSelector:@selector(grabSomethingWithCompletion:) argumentIndex:0 ofReply:YES];

现在这应该可以使这个数组可以安全地跨进程复制并在另一端解码。不幸的是,这似乎没有按预期工作。

在导出的协议上调用该方法时,我收到一个异常:

警告:在解码收到的对消息“grabSomethingWithCompletion:”的回复、丢弃传入消息和调用失败块时捕获异常。

异常:解码调用参数 1 时出现异常:返回值:{v} void 目标:{@?} 0x0(块)参数 1:{@} 0x0

例外:键“NS.objects”的值是意外的“Foo”类。允许的类是'{( NSNumber, NSArray, NSDictionary, NSString, NSDate, NSData )}'。

这似乎甚至没有注册我之前执行的白名单。有什么想法吗?

4

3 回答 3

15

编辑 2:这取决于您将其列入白名单的位置Foo。它需要从正在调用的任何内容中列入白名单grabSomethingWithCompletion:。例如,如果您有一个实现和公开的服务:

- (void)takeThese:(NSArray *)bars reply:(void (^)(NSArray *foos))completion;

然后您需要服务端Bar将传入连接列入白名单:

// Bar and whatever Bar contains.
NSSet *incomingClasses = [NSSet setWithObjects:[Bar class], [NSString class], nil];
NSXPCInterface *exposedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(InYourFaceInterface)];
[exposedInterface setClasses:incomingClasses forSelector:@selector(takeThese:reply:) argumentIndex:0 ofReply:NO];

// The next line doesn't do anything.
[exposedInterface setClasses:incomingClasses forSelector:@selector(takeThese:reply:) argumentIndex:0 ofReply:YES];
xpcConnection.exposedInterface = exposedInterface;

第二部分必须在连接的另一端进行,无论与您的服务交谈:

NSSet *incomingClasses = [NSSet setWithObjects:[Foo class], [NSNumber class], nil];
NSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(InYourFaceInterface)];
[remoteObjectInterface setClasses:incomingClasses forSelector:@selector(takeThese:reply:) argumentIndex:0 ofReply:YES];
xpcConnection.remoteObjectInterface = remoteObjectInterface;

总之,任何接收到奇怪对象的东西都需要将奇怪对象列入白名单。不确定这是否是您的问题,但我敢肯定它会是某人的问题。

编辑:现在我已经与 XPC 合作了一段时间,我意识到我的回答在解决问题时并不能解决您的问题。我现在已经遇到了几次不同的情况,但我仍然不确定如何在实现我自己的集合类之外解决它,这不太理想。

原始答案:我知道你问这个问题已经有一段时间了,但是经过大量搜索而没有人回答这个问题,我想我会发布我的答案来说明导致它的原因(可能还有其他原因,但是这为我修好了)。

在符合 的类中NSSecureCoding,在initWithCoder:方法中,您需要通过传入集合中包含的所有可能类的集合来显式解码集合。前两个是解码的标准示例,最后一个是解码集合:

if (self = [super init]) {
    self.bar = [aDecoder decodeInt64ForKey:@"bar"];
    self.baz = [aDecoder decodeObjectOfClass:[Baz class] forKey:@"baz"];
    NSSet *possibleClasses = [NSSet setWithObjects:[Collection class], [Foo class], nil];
    self.foo = [aDecoder decodeObjectOfClasses:possibleClasses forKey:@"foo"];
}

因此,如果您的集合是包含 NSStrings 的集合,则可能的类将是[NSSet class]and [NSString class]

我相信你已经从这个问题中走了出来,但也许其他人和我一样需要这个答案。

于 2013-12-23T21:08:38.770 回答
1

我遇到了同样的问题,我也必须明确列入白NSArray*名单

NSSet *classes = [NSSet setWithObjects: [Foo class], [NSArray class], nil];

这有点违反直觉,因为文档没有提到这个要求。

于 2014-02-07T21:17:41.820 回答
0

实际上,您似乎需要将自定义类添加到已经列入白名单的类中:

NSSet currentClasses = [remoteObjectInterface classesForSelector:@selector(takeThese:reply:) argumentIndex:0 ofReply:YES];


NSSet *allIncomingClasses = [currentClasses setByAddingObjectsFromSet:[NSSet setWithObjects:[Foo class], [NSNumber class], nil];

NSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(InYourFaceInterface)];
[remoteObjectInterface setClasses:allIncomingClasses forSelector:@selector(takeThese:reply:) argumentIndex:0 ofReply:YES];
xpcConnection.remoteObjectInterface = remoteObjectInterface;
于 2015-05-21T16:36:55.007 回答