你如何使 Swift class 在 XPC 服务中可用?

How do you make a Swift class available in an XPC service?

我正在尝试将 Apple 的 XPC "lowerCase" 示例代码从 Objective-C 重建为 Swift。我知道 XPC 会,但我对 Swift 和 Objective-C 互操作性还比较陌生。

当我使用他们的确切示例代码时,它将 String 从应用程序传递到目标并返回,它起作用了。但是当我尝试用我自己的自定义 class、Person 替换它时,我收到错误:

NSXPCConnection: ... connection on anonymousListener or serviceListener from pid 4133:

Exception caught during decoding of received selector upperCasePerson:withReply:, dropping incoming message.

Exception: Exception while decoding argument 0 (#2 of invocation):

Exception: decodeObjectForKey: class "CombineCycle.Person" not loaded or does not exist.

(演示应用程序名称是 'CombineCycle')

Person是一个Swiftclass,继承自NSObject,符合NSSecureCodingname: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 的实例,因此包含了 class。问题似乎是 NSXPCDecoder(私有 class)无法反序列化它...

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

这些问题似乎与 NSCoder 如何根据类的名称进行归档和取消归档有关。当 Person 对象在应用程序端编码时,使用的名称是 <ModuleName.ClassName>

当试图在服务中反序列化时,ModuleName 自然是错误的。在 Person 上使用 @objc(Person) 来设置 Objective-C 名称似乎有效。