【问题标题】:Using custom class in XPC protocol在 XPC 协议中使用自定义类
【发布时间】:2017-02-12 04:33:12
【问题描述】:

我正在尝试在 withReply 签名上使用我自己的类型编写 XPC 服务。类型/类具有 Xcode 的主应用程序和 XPC 服务的“目标成员资格”。然而,我在调试输出中得到了incompatible reply block signature,即使在withReply 签名中使用了相同的类,但是Xcode 目标不同,我将在下面解释。

注意:这是在 Swift 中使用 this project 来完成的。除了那里他们使用NSData 而不是自定义类型。

详情

出于这个问题的目的,我将使用以下示例

  • 自定义类 - Tweet - 该类符合 NSSecureCoding 协议,因此可以在主应用程序和 XPC 服务之间传递
  • XPC 协议 - TweetTransfer 需要一种方法 func take(_ count: Int, withReply: ((Tweet) -> Void))

然后是我导出符合TweetTransfer 的对象的所有常用XPC 样板。 XPC 服务似乎已启动,但随后在它和主应用程序之间传输失败并显示

XPCWorker[11069:402719] <NSXPCConnection: 0x61800010e220> connection from pid 11066 received an undecodable message

完整的消息在下面[1],但“wire”和“local”之间的唯一区别是第一个参数是

  • 电汇-_TtC17MainApp5Tweet
  • 本地 - _TtC23XPCWorker5Tweet

Xcode 目标不同的地方。这足以扔掉它吗?那么如何在应用和它的 XPC 服务之间共享代码呢?

[1] 完整的错误文本

<NSXPCConnection: 0x61800010e220> connection from pid 11066 received an undecodable message (incompatible reply block signature (wire: <NSMethodSignature: 0x618000074ec0>
    number of arguments = 2
    frame size = 224
    is special struct return? NO
    return value: -------- -------- -------- --------
        type encoding (v) 'v'
        flags {}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0}
        memory {offset = 0, size = 0}
    argument 0: -------- -------- -------- --------
        type encoding (@) '@?'
        flags {isObject, isBlock}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0}
        memory {offset = 0, size = 8}
    argument 1: -------- -------- -------- --------
        type encoding (@) '@"_TtC17MainApp5Tweet"'
        flags {isObject}
        modifiers {}
        frame {offset = 8, offset adjust = 0, size = 8, size adjust = 0}
        memory {offset = 0, size = 8}
            class '_TtC17MainApp5Tweet'
 vs local: <NSMethodSignature: 0x610000074740>
    number of arguments = 2
    frame size = 224
    is special struct return? NO
    return value: -------- -------- -------- --------
        type encoding (v) 'v'
        flags {}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 0, size adjust = 0}
        memory {offset = 0, size = 0}
    argument 0: -------- -------- -------- --------
        type encoding (@) '@?'
        flags {isObject, isBlock}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 8, size adjust = 0}
        memory {offset = 0, size = 8}
    argument 1: -------- -------- -------- --------
        type encoding (@) '@"_TtC23XPCWorker5Tweet"'
        flags {isObject}
        modifiers {}
        frame {offset = 8, offset adjust = 0, size = 8, size adjust = 0}
        memory {offset = 0, size = 8}
            class '_TtC23XPCWorker5Tweet'
)

更新

有关协议、remoteObjectProxy 连接和 Tweet 对象的更多信息。这是用于 XPC 调用的协议:

@objc(TweetTransfer)
protocol TweetTransfer {
  func take(_ count: Int, withReply: replyType)
}

typealias replyType = ((Tweet) -> Void)

为方便起见,我使用了类型别名。然后Tweet 对象非常简单,仅用于测试(虽然支持 NSSecureCoding 有点复杂):

final class Tweet: NSObject, NSSecureCoding {
  var name: String
  var text: String
  static var supportsSecureCoding = true

  init(name: String, text: String) {
    self.name = name
    self.text = text
  }

  init?(coder aDecoder: NSCoder) {
    guard let name = aDecoder.decodeObject(forKey: "name") as? String else {
      fatalError("Could not deserialise name!")
    }

    guard let text = aDecoder.decodeObject(forKey: "text") as? String else {
      fatalError("Could not deseralise text!")
    }

    self.name = name
    self.text = text
  }

  func encode(with aCoder: NSCoder) {
    aCoder.encode(name, forKey: "name")
    aCoder.encode(text, forKey: "text")
  }
}

最后是我们调用 remoteObjectProxy 的地方

guard let loader = workerConnection.remoteObjectProxyWithErrorHandler(handler) as? TweetTransfer else {
  fatalError("Could not map worker to TweetTransfer protocol!")
}

var tweets = [Tweet]()
loader.take(1) { tweet in
  tweets.append(tweet)
}

【问题讨论】:

  • 我也许可以帮助你。几天前实际上只是在处理这个问题,但是在objective-c中。您能否将发件人发送消息的代码发布到连接的remoteObjectProxy?以及 Tweet 类的标头和实现
  • 谢谢,我已经添加了更多信息。
  • 您找到解决方案了吗?

标签: xcode macos nsxpcconnection


【解决方案1】:

完整的消息如下,但“wire”和“local”之间的唯一区别是第一个参数是

  • 电线 - _TtC17MainApp5Tweet
  • 本地 - _TtC23XPCWorker5Tweet

Xcode 目标不同的地方。这足以扔掉它吗?那么如何在应用和它的 XPC 服务之间共享代码呢?

这确实足以摆脱它。 Swift 的命名空间使归档对象显示为不同的类。您可以通过声明您的 Tweet 对象来禁用名称间距;

@objc(Tweet) class Tweet: NSObject, NSSecureCoding { ... }

@objc(name) 中的 name 通常作为在 objc 与 Swift 中呈现不同名称的一种方式,但它也具有禁用 Swift 名称间距的效果。

来自Using Swift with Cocoa and Objective-C

当您在 Swift 类上使用 @objc(name) 属性时,该类在 Objective-C 中可用,无需任何命名空间。因此,在将可归档的 Objective-C 类迁移到 Swift 时,此属性也很有用。因为归档对象在归档中存储其类的名称,所以您应该使用 @objc(name) 属性指定与您的 Objective-C 类相同的名称,以便新的 Swift 类可以取消归档旧的归档。

另一种选择是将您的自定义对象移动到框架。然后该框架目标成为命名空间,XPC 和 App 都将引用框架中的相同命名空间/类。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-12
    • 2021-03-09
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 2019-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多