在XPC协议中使用自定义类 [英] Using custom class in XPC protocol

查看:119
本文介绍了在XPC协议中使用自定义类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用自己在withReply签名上的类型来编写XPC服务.类型/类具有Xcode的主应用程序和XPC服务的目标成员身份".但是,即使在withReply签名中使用了相同的类,我也在调试输出中得到了incompatible reply block signature,但是Xcode目标有所不同,如下所述.

I’m attempting to write an XPC service using my own type on the withReply signature. The type/class has Xcode’s "target membership" of both the main app and the XPC service. However I am getting incompatible reply block signature in the debug output even though the same class is being used in the withReply signature however the Xcode target differs as I will explain below.

注意:这是使用此项目在Swift中完成的让我开始.除了那里,他们使用NSData而不是自定义类型.

Note: This is being done in Swift using this project to get me started. Except there they use NSData instead of a custom type.

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

For the purposes of this question I’ll use the following as an example

  • 自定义类-Tweet-此类符合NSSecureCoding协议,因此可以在主应用程序和XPC服务之间传递
  • XPC协议-TweetTransfer,其中一种方法要求func take(_ count: Int, withReply: ((Tweet) -> Void))
  • Custom class - Tweet - This class conforms to the NSSecureCoding protocol so that it can be passed between the main app and the XPC service
  • XPC Protocol - TweetTransfer with one method required func take(_ count: Int, withReply: ((Tweet) -> Void))

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

and then all the usual XPC boilerplate where I export an object conforming to TweetTransfer. The XPC service appears to launch but then transfer between it and the main app fails with

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

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

The full message is below[1] but the only difference between the "wire" and "local" is that argument one is

  • 电线-_TtC17MainApp5Tweet
  • 本地-_TtC23XPCWorker5Tweet
  • wire - _TtC17MainApp5Tweet
  • local - _TtC23XPCWorker5Tweet

Xcode目标不同的地方.这足以把它扔掉吗?然后如何在应用程序和它的XPC服务之间共享代码?

Where the Xcode target is different. Is that enough to throw it off? How then do I share code between an app and it's XPC service?

[1]完整的错误文本

[1] Full error text

<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调用所使用的协议:

Update

Some more info regarding the protocol, remoteObjectProxy connection and Tweet object. This is the protocol used for the XPC calls:

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

typealias replyType = ((Tweet) -> Void)

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

I'm using a type alias for convenience. And then the Tweet object is very simple and just for testing (although somewhat complicated by supporting 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的点

and finally the point at which we call the 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)
}

推荐答案

下面是完整的消息,但是"wire"和"local"之间的唯一区别是参数一个是

The full message is below but the only difference between the "wire" and "local" is that argument one is

  • 电线-_TtC17MainApp5Tweet
  • 本地-_TtC23XPCWorker5Tweet
  • wire - _TtC17MainApp5Tweet
  • local - _TtC23XPCWorker5Tweet

Xcode目标不同的地方.这足以把它扔掉吗?然后如何在应用程序和它的XPC服务之间共享代码?

Where the Xcode target is different. Is that enough to throw it off? How then do I share code between an app and it's XPC service?

这确实足以把它扔掉. Swift的命名空间使已归档的对象显示为不同的类.您可以通过以下方式声明您的Tweet对象来禁用名称间隔:

That is indeed enough to throw it off. Swift's namespacing makes the archived object appear as a different class. You can disable name spacing by declaring your Tweet object with;

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

@objc(name)中的名称通常被用作在objc和Swift中呈现不同名称的一种方式,但是它也具有禁用Swift的名称间距的作用.

The name in @objc(name) is often presented as a way to present a different name in objc vs Swift, but it also has the effect of disabling Swift's name spacing.

来自

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

When you use the @objc(name) attribute on a Swift class, the class is made available in Objective-C without any namespacing. As a result, this attribute can also be useful when migrating an archivable Objective-C class to Swift. Because archived objects store the name of their class in the archive, you should use the @objc(name) attribute to specify the same name as your Objective-C class so that older archives can be unarchived by your new Swift class.

另一种替代方法是将您的自定义对象移至Framework.然后,该框架目标将成为名称空间,并且XPC和App都将引用框架中的相同名称空间/类.

Another alternative is to move your custom object to a Framework. That framework target then becomes the namespace, and both the XPC and App would refer to the same namespace/class in the framework.

这篇关于在XPC协议中使用自定义类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆