【问题标题】:Swift 4 Codable: Cannot exclude a propertySwift 4 Codable:无法排除属性
【发布时间】:2017-08-07 23:52:41
【问题描述】:

我正在开发一个简单的音乐音序器应用程序。这种应用程序往往具有复杂的数据结构,必须保存/加载,所以在 Swift4 中引入Codable 协议对我来说完全是一个好消息。

我的问题是: 我必须有一个不可编码的属性。它不必编码,因为它是一个临时变量,仅在应用程序处于活动状态时才保持活动状态。 所以我刚刚尝试通过实现CodingKey 来排除,但编译器仍然给我错误“类型'Song'不符合协议'Decodable'”。

具体来说,我想在下面的代码中排除“musicSequence”。

class Song : Codable { //Type 'Song' does not conform to protocol 'Decodable'
    var songName : String = "";    
    var tempo : Double = 120;

    // Musical structure
    var tracks : [Track] = [] // "Track" is my custom class, which conforms Codable as well    
    // Tones
    var tones = [Int : ToneSettings] (); // ToneSettings is also my custom Codable class

    var musicSequence : MusicSequence? = nil; // I get the error because of this line

    private enum CodingKeys: String, CodingKey {
        case songName
        case tempo
        case tracks
        case tones
    }

    func createMIDISequence () {
        // Create MIDI sequence based on "tracks" above
        // and keep it as instance variable "musicSequence"
    }
}

有人有什么想法吗?

【问题讨论】:

  • 据我在 Xcode 9 beta 5 上测试,您的代码编译没有问题,并且可以在没有“musicSequence”的情况下从/编码到 JSON 数据。如果您尝试使用较旧的测试版,则可能是较旧的测试版的错误。如果您使用 beta 5 测试您的代码并得到您描述的错误,则其他一些部分可能会影响,因此您需要显示更多上下文来重现该问题。请检查。
  • 我发现我还在使用 beta3。它是用 beta5 编译的!谢谢

标签: ios swift4 codable


【解决方案1】:

(请参阅下面的奇怪事件。)

您对CodingKeys 的使用已经在处理您的编码问题。你仍然可以免费获得。但是您需要告诉系统如何手动处理解码:

required init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    songName = try values.decode(String.self, forKey: .songName)
    tempo = try values.decode(Double.self, forKey: .tempo)
    tracks = try values.decode([Track].self, forKey: .tracks)
    tones = try values.decode([Int: ToneSettings].self, forKey: .tones)
}

它还不够相当聪明地发现musicSequence 可以而且应该默认为nil(也许这也太聪明了)。

可能值得在 bugs.swift.org 上打开一个缺陷来要求这个 Decodable 是自动的。在您提供CodingKeys 并且有默认值的情况下,它应该能够弄清楚。


编辑:当我第一次回答这个问题时,我完全重复了你的错误。但是当我再次尝试重新复制您的代码时,错误不会出现。以下代码在 Playground 中编译并运行:

import Foundation

struct Track: Codable {}
struct ToneSettings: Codable {}
struct MusicSequence {}

class Song : Codable { //Type 'Song' does not conform to protocol 'Decodable'
    var songName : String = "";
    var tempo : Double = 120;

    // Musical structure
    var tracks : [Track] = [] // "Track" is my custom class, which conforms Codable as well
    // Tones
    var tones = [Int : ToneSettings] (); // ToneSettings is also my custom Codable class

    var musicSequence : MusicSequence? = nil; // I get the error because of this line

    private enum CodingKeys: String, CodingKey {
        case songName
        case tempo
        case tracks
        case tones
    }

    func createMIDISequence () {
        // Create MIDI sequence based on "tracks" above
        // and keep it as instance variable "musicSequence"
    }
}

let song = Song()
let data = try JSONEncoder().encode(song)
String(data: data, encoding: .utf8)

let song2 = try JSONDecoder().decode(Song.self, from: data)

我想知道这里是否存在编译器错误;请务必使用新的测试版对此进行测试。

【讨论】:

  • 正如我在上面所评论的,它符合 beta5。但是您的信息仍然有用。谢谢!
  • 亲爱的@Takeshi Yokemura 正如 Rob Napier 所说,它在 xcode9 GM 中完美运行,没有任何编译错误。关键是我们应该将不可编码的键设为可选并分配一个默认值。
猜你喜欢
  • 2017-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-25
  • 2018-01-25
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
相关资源
最近更新 更多