如何在 XPC 服务中提供 Swift 类?

Posted

技术标签:

【中文标题】如何在 XPC 服务中提供 Swift 类?【英文标题】:How do you make a Swift class available in an XPC service? 【发布时间】:2019-06-13 17:29:22 【问题描述】:

我正在尝试将 Apple 的 XPC“小写”示例代码从 Objective-C 重建为 Swift。我了解 XPC 会,但我对 Swift 和 Objective-C 互操作性还比较陌生。

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

NSXPCConnection: ...匿名侦听器上的连接或 来自 pid 4133 的服务监听器:

在解码接收到的选择器 upperCasePerson:withReply: 时捕获异常,丢弃传入的 消息。

异常:解码参数 0 时出现异常(#2 of 调用):

异常:decodeObjectForKey:类 “CombineCycle.Person”未加载或不存在。

(演示应用名称为“CombineCycle”)

Person 是一个继承自NSObject 并符合NSSecureCoding 的Swift 类。它有一个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

【问题讨论】:

我还没有使用 NSXPCConnection,但我猜你必须用 @objc 标记所有类/属性。 你检查过这个matthewminer.com/2018/08/25/… 吗? 我确实引用了该资源,并且与 Apple 示例代码一样,它使用 String 作为传输。这很好用,但是如果我用Person(这是我的 Swift 类)替换 String,那么我会遇到异常。如果我将@objc 添加到Person 类,它似乎没有帮助。我需要更改任何构建设置吗?上面的参考实际上需要进行一些更改才能使 Swift 正常工作。也许我忽略了桥接头的其他内容...... 【参考方案1】:

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

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

【讨论】:

感谢您提供这方面的好信息。但即使在使用@objc(Person) 之后,我仍然会收到相同的错误:'异常:decodeObjectForKey:类“Person”未加载或不存在'。 Person 源代码包含在两个目标中。与您的情况一样,如果我使用 String 而不是 Person,一切正常。有什么想法吗? 很难保留您可能遇到的问题,但我会尝试在您的 XPC 目标中实例化一个 Person 对象,以确保 XPC 目标确实具有适当的包括的课程。请务必从 Swift 文件和 ObjC 文件进行测试。这应该有助于缩小问题的范围。还值得检查以确保您允许通过 NSSecureCoding 方法解码 Person 类。 如果有人需要更多信息来说明如何在这里使用@objc,这篇文章让我明白了 - developer.apple.com/forums/thread/7296

以上是关于如何在 XPC 服务中提供 Swift 类?的主要内容,如果未能解决你的问题,请参考以下文章

NSSecureCoding 实现类必须在共享框架中才能与 XPC 一起使用吗?

谈谈Mac进程间通信--XPC

如何在macOS上使用MTLSharedTextureHandle或MTLSharedEventHandle与C XPC接口?

应该如何编写带状态的 XPC 服务?

XPC 连接如何以线程方式处理?

如何禁用加载/激活 macOS xpc 服务?