XPC неправильно регистрирует классы для сбора

Я использую XPC в одном из своих приложений на 10.8. Он имеет стандартную настройку с протоколами, определенными для экспортируемого интерфейса и удаленного интерфейса. Проблема, с которой я сталкиваюсь, связана с одним из моих методов в экспортированном интерфейсе.

У меня есть класс модели, давайте просто назовем его 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 target: {@?} 0x0 (блок) аргумент 1: {@} 0x0

Исключение: значение ключа «NS.objects» имело непредвиденный класс «Foo». Допустимые классы: '{(NSNumber, NSArray, NSDictionary, NSString, NSDate, NSData)}'.

Это почти похоже на то, что он даже не зарегистрировал белый список, который я выполнил ранее. Есть предположения?


person sudo rm -rf    schedule 27.05.2013    source источник
comment
Похоже, что это также нужно сделать NSPropertyListSerialization. Также кажется, что вы не одиноки   -  person CodaFi    schedule 27.05.2013


Ответы (3)


РЕДАКТИРОВАНИЕ 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;

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

EDIT: теперь, когда я работаю с 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] и [NSString class].

Я уверен, что вы ушли от этой проблемы, но, возможно, кому-то еще нужен этот ответ так же, как и мне.

person DrGodCarl    schedule 23.12.2013
comment
Моя проблема была решена вашим оригинальным ответом. Пока я использую XPC, проблема с белым списком, с которой я столкнулся, была в реализации NSCoding. Я декодировал словарь, и у меня был только белый список NSDictionary, но мне нужно было внести в белый список возможные типы значений внутри словаря, как вы показываете в своем примере. Спасибо. - person Andrew; 04.10.2015
comment
@ Эндрю - Да, я оставил все здесь, потому что все они проявляют свои проблемы очень похожим образом. Рад, что хотя бы один из моих трех ответов может помочь. - person DrGodCarl; 06.10.2015
comment
Оригинальный ответ также решил эту проблему для меня. У меня был NSMutableArray строк в моем пользовательском объекте, и я использовал -decodeObjectOfClass:[класс NSMutableArray] вместо использования метода -decodeObjectOfClasses:forKey:. - person Bryan; 01.03.2017
comment
Что ж, я рад быть полезным. - person DrGodCarl; 07.03.2017

Я столкнулся с той же проблемой, мне также пришлось явно добавить NSArray* в белый список.

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

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

person Sam Miller    schedule 07.02.2014

На самом деле кажется, что вам нужно добавить свой собственный класс к уже внесенным в белый список:

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;
person Guillaume Laurent    schedule 21.05.2015