Reputation: 425
I'm developing a simple music sequencer app. This kind of app tends to have a complex data structure which has to be saved/loaded, so the introduction of Codable
protocol in Swift4 is totally a good news for me.
My problem is this:
I have to have a non-Codable property. It doesn't have to be coded because it's a temporary variable only kept alive while the app is active.
So I've just tried to exclude by implementing CodingKey
, but the compiler still give me the error "Type 'Song' does not conform to protocol 'Decodable'".
Specifically I want to exclude "musicSequence" in the code below.
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"
}
}
Does anybody have any ideas?
Upvotes: 4
Views: 2968
Reputation: 299345
(See below for a strange turn of events.)
Your use of CodingKeys
is already taking care of you encoding. You still get that for free. But you'll need to tell the system how to handle decoding by hand:
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)
}
It's not quite smart enough to figure out that musicSequence
can and should default to nil
(and maybe that would be too smart anyway).
It's probably worth opening a defect at bugs.swift.org to ask for this Decodable to be automatic. It should be able to figure it out in cases where you provide CodingKeys
and there is a default value.
EDIT: When I first answered this, I exactly duplicated your error. But when I tried to do it again, copying your code fresh, the error doesn't show up. The following code compiles and runs in a 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)
I'm wondering if there's a compiler bug here; make sure to test this with the new beta.
Upvotes: 6