Как сделать класс Swift доступным в службе XPC?

Я пытаюсь перестроить образец кода Apple XPC "lowerCase" с Objective-C на Swift. Я понимаю, что XPC будет, но я относительно новичок в совместимости Swift и Objective-C.

Когда я использую их точный пример кода, который передает String от приложения к цели и обратно, он работает. Но когда я пытаюсь заменить его своим собственным классом Person, я получаю сообщение об ошибке:

NSXPCConnection: ... подключение к anonymousListener или serviceListener из pid 4133:

Исключение при декодировании полученного селектора upperCasePerson: withReply :, отбрасывающего входящее сообщение.

Исключение: исключение при декодировании аргумента 0 (№2 вызова):

Исключение: decodeObjectForKey: класс «CombineCycle.Person» не загружен или не существует.

(Название демонстрационного приложения - CombineCycle)

Person - это класс Swift, который наследуется от NSObject и соответствует NSSecureCoding. Он имеет единственное свойство для name:String. Сопровождающий .swift исходный файл включен в сборку целевого объекта XPC.

Исключение кажется довольно очевидным, но я не уверен, какие настройки сборки мне нужно изменить или какие файлы мне нужно сгенерировать, чтобы исправить основную проблему.

Это просто демонстрационное приложение. Основное приложение было создано как приложение Swift и не содержит файлов Objective-C. Цель XPC была создана с использованием новой целевой функции Xcode, которая в Xcode 11 генерирует скелет Objective-C. Я заменил все эти файлы реализациями Swift.

// Person.swift (Included in both targets)

@objc public class Person : NSObject, NSSecureCoding  {
  var name:String?

  init(_ name:String) {
    self.name = name
  }

  public static var supportsSecureCoding: Bool {
    return true
  }

  public required init?(coder: NSCoder) {
    self.name = coder.decodeObject(forKey: "name") as? String
  }

  public func encode(with coder: NSCoder) {
    coder.encode(self.name, forKey: "name")
  }
}

Обновить

Служба XPC прекрасно может создать экземпляр Person, поэтому класс уже включен. Проблема заключается в том, что NSXPCDecoder (частный класс) не может десериализовать его ...

    __exceptionPreprocess + 250
    objc_exception_throw + 48
    _decodeObject + 1413
    -[NSXPCDecoder _decodeObjectOfClasses:atObject:] + 63
    _NSXPCSerializationDecodeInvocationObjectOnlyArgumentArray + 463

person kennyc    schedule 13.06.2019    source источник
comment
Я еще не работал с NSXPCConnection, но предполагаю, что вам нужно пометить все классы / свойства с помощью @objc.   -  person Martin R    schedule 13.06.2019
comment
Вы проверяли это matthewminer.com/2018/ 25 августа /?   -  person Martin R    schedule 13.06.2019
comment
Я сослался на этот ресурс, и, как и в примере кода Apple, он использует String в качестве транспорта. Это отлично работает, но если я заменю String на Person, который является моим классом Swift, я получу исключение. Если я добавлю @objc к классу Person, это не поможет. Есть ли какие-то настройки сборки, которые мне нужно изменить? Приведенная выше ссылка на самом деле требует нескольких изменений, чтобы Swift в целом работал. Возможно, я упустил из виду что-то еще вроде переходного заголовка ...   -  person kennyc    schedule 13.06.2019


Ответы (1)


Проблемы, по-видимому, связаны с тем, как NSCoder выполняет архивирование и разархивирование, полагаясь на имя класса. Когда объект Person кодируется на стороне приложения, используется имя <ModuleName.ClassName>.

При попытке десериализации этого в сервисе ModuleName, естественно, ошибочен. Использование @objc(Person) на человеке для установки имен Objective-C, похоже, работает.

person kennyc    schedule 13.06.2019
comment
Спасибо за хорошую информацию по этому поводу. Но даже после использования @objc (Person) я продолжаю получать ту же ошибку: «Exception: decodeObjectForKey: class Person не загружен или не существует». Исходный код Person включен в обе цели. Как и в вашем случае, все работает нормально, если я использую String вместо Person. Любые идеи? - person rene; 09.03.2021
comment
Трудно решить, какие проблемы могут возникнуть у вас, но я бы попытался создать экземпляр объекта Person в вашей цели XPC где-нибудь в общем, просто чтобы убедиться, что цель XPC действительно включает соответствующие классы. Обязательно протестируйте из файла Swift и файла ObjC. Это должно помочь сузить проблему. Также стоит проверить, разрешено ли декодирование Person классов с помощью NSSecureCoding методов. - person kennyc; 14.03.2021
comment
Если кому-то нужно немного больше информации, чтобы прояснить, как использовать здесь @objc, эта статья меня туда привела - developer.apple.com/forums/thread/7296 - person Chris; 28.05.2021