Как сделать класс Swift доступным в службе XPC? - PullRequest
0 голосов
/ 13 июня 2019

Я пытаюсь перестроить пример кода 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

1 Ответ

2 голосов
/ 14 июня 2019

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

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

...