2017-08-07 63 views
1

我正在開發一個簡單的音樂音序器應用程序。這種應用程序往往有一個複雜的數據結構,必須保存/加載,因此在Swift4中引入Codable協議對我來說完全是一個好消息。Swift4 Condable:不能排除一個屬性

我的問題是這樣的: 我必須有一個非Codable屬性。它不必被編碼,因爲它是一個只在應用程序處於活動狀態時保持活動狀態的臨時變量。 所以我試圖通過執行CodingKey來排除,但編譯器仍然給我錯誤「Type'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" 
    } 
} 
+0

據我測試Xcode 9 beta 5,你的代碼編譯沒有問題,可以解碼從/編碼到JSON數據沒有「musicSequence」。如果您嘗試使用較舊的測試版,則可能是較舊的測試版的一個缺陷。如果您使用beta 5測試了您的代碼並獲取了您描述的錯誤,則其他部分可能會受到影響,因此您需要展示更多上下文才能重現問題。請檢查。 – OOPer

+0

我發現我還在使用beta3。它用beta5編譯!謝謝 –

回答

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並且有默認值,它應該能夠計算出來。


編輯:當我第一次回答這個問題時,我完全重複了你的錯誤。但是當我嘗試再次執行時,將新代碼複製,錯誤不會顯示出來。下面的代碼編譯,並在操場上運行:

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) 

我想知道如果這裏有一個編譯器的bug;請務必使用新的測試版進行測試。

+0

正如我上面所評論的,它符合beta5。但您的信息仍然有用。謝謝! –

+0

親愛的@Takeshi Yokemura正如Rob Napier所說,它在xcode9 GM中完美工作,沒有任何編譯錯誤。關鍵是我們應該將非可編碼密鑰設置爲可選項並指定默認值。 –