无法取消存档手表发送的文件

Can't unarchive a file sent by watch

我有一个 class 包含在 Apple Watch 上生成的数据。我使用下面的方法来归档class,将数据存储在一个文件中,然后将文件发送到iPhone。

func send(file counter: CounterModel) {
    let session = WCSession.default
    let fm = FileManager.default
    let documentsDirectory = fm.urls(for: .documentDirectory, in: .userDomainMask).first!
    let transferStore = documentsDirectory.appendingPathComponent("transferfile").appendingPathExtension("cnt")

    do {
        let counterData = try NSKeyedArchiver.archivedData(
            withRootObject: counter,
            requiringSecureCoding: false
        )
        try counterData.write(to: transferStore)
        if session.activationState == .activated {
            session.transferFile(transferStore, metadata: nil)
        }
    } catch {
        print("Oops")
    }
}

将文件发送到 iPhone 工作正常,正在调用委托方法并接收文件。但是,我无法取消存档数据并收到错误消息“无法读取数据,因为它的格式不正确。”代表很简单:

func session(_ session: WCSession, didReceive file: WCSessionFile) {

    do {
        let contents = try Data(contentsOf: file.fileURL)
        
        if let newValue = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(contents) as? CounterModel {
            listOfCounters.append(newValue)
        } else {
            print("The content could not be decoded.")
        }
    } catch {
        print("Failed to retrieve the file with error \(error.localizedDescription).")
    }
}

显然,我做错了什么。 iPhone 上的数据取消存档有效,所以这不是问题所在。也许发送的文件有另一种格式,但我无法获得任何相关信息。

我将问题作为 DTS 的票证打开并得到以下答案:

The culprit is that your Model class has a different (full) class name in different targets. A Swift class has a module name, which by default is tied to the target name. When your Model class is compiled for your WatchKit extension, its full name is “TagetName_watchkit_extension.Model”; when it is compiled for your iOS app, it becomes “TargetName.Model”.

When your WatchKit extension archives an object Model, it uses “Target_watchkit_extension.Model” as the class name, which is not recognized by your iOS app, and triggers the failure.

You can use @objc to give your Model class a full name, which prevents the compiler from adding the module name, like below:

@objc(Model)
class Model: NSObject, NSCoding, ObservableObject {

我实施了这个建议并且奏效了。但是,在我的 MacBook 上,我从预览中收到一条错误消息,指出我需要更改带有“@objc dynamic”前缀的模型的某些方法。然而,这可能会发生,因为 Apple 的 DTS 没有收到此错误。

对该问题的回复是:

“@objc dynamic” is required for KVO (key-value observation) support. Since a “@Published" variable relies on KVO as well, adding that does sound reasonable for me.

这解决了我的问题,我很高兴。