2017-03-26 12 views
1

オブジェクトをエンコードしようとしていますが、いくつか問題があります。文字列、ブール値などでは問題なく動作しますが、enumにどのように使用するのか分かりません。関連付けられた値でenumをアーカイブするには?

enum Creature: Equatable { 
    enum UnicornColor { 
     case yellow, pink, white 
    } 

    case unicorn(UnicornColor) 
    case crusty 
    case shark 
    case dragon 

私はエンコードのために、このコードを使用しています:ここで

func saveFavCreature(creature: Dream.Creature) { 
    let filename = NSHomeDirectory().appending("/Documents/favCreature.bin") 
    NSKeyedArchiver.archiveRootObject(creature, toFile: filename) 
} 

func loadFavCreature() -> Dream.Creature { 
    let filename = NSHomeDirectory().appending("/Documents/favCreature.bin") 
    let unarchived = NSKeyedUnarchiver.unarchiveObject(withFile: filename) 

    return unarchived! as! Dream.Creature 
} 

は、必要な機能(model.favoriteCreature == Dream.Creature)

override func encode(with aCoder: NSCoder) { 
    aCoder.encode(model.favoriteCreature, forKey: "FavoriteCreature") 
    aCoder.encode(String(), forKey: "CreatureName") 


} 

required init?(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    let favoriteCreature = aDecoder.decodeObject(forKey: "FavoriteCreature") 
    let name = aDecoder.decodeObject(forKey: "CreatureName") 
} 
である私はこれをエンコードする必要があり

これは "name"とうまく動作しますが、問題はaCoder.encode()にあります。私はそこに書き込むタイプがわかりません。 - [_ SwiftValue encodeWithCoder:]:インスタンスに送信された認識できないセレクタ - [NSKeyedArchiver dealloc]:警告:NSKeyedArchiverは、-finishEncodingを呼び出さずに割り当てを解除しました。

私はコメントでいくつかのアドバイスを読んで、私は列挙型クリーチャーにはrawValuesを持っていないと仮定することができ、私はその列挙中生タイプ「string」を作っ:

enum Creature: String, Equatable { 
    enum UnicornColor { 
     case yellow, pink, white 
    } 

    case unicorn(UnicornColor) 
    case crusty 
    case shark 
    case dragon 

今、私はこのエラーを持っている:生と 列挙型は引数を持つ大文字小文字を持つことはできません また、関連する値と生の値が混在することはありません。おそらく、生の値を持たないenumをアーカイブする別の方法がありますか?

誰かが私を助けることを願って、あなたの問題のために感謝の

+0

が、 'NSHomeDirectory()を使用して。あなたのパスを構築するために、'( "/ドキュメント/ favCreature.bin")を追加することは間違っています。多くの適切な例を見つけるために 'documentDirectory'を検索してください。 – rmaddy

+0

ありがとう! –

+0

「rawValue」をエニュメレーションに関連付け、encore/decodeする必要があります。 – Paulw11

答えて

1

主な問題は、あなたがencode(_:forKey:)にスウィフト列挙型を渡すことができないということです。

This articleがこの部分を解決するのに役立ちます。列挙型が簡単にrawValueを持つことができれば、あまり難しくありません。

しかし、あなたが見るように、生の型の列挙型は、引数を持つ大文字小文字を持つことはできません。

単純な列挙型は、簡単にこのようなrawValueを持つことができます。

enum UnicornColor: Int { 
     case yellow, pink, white 
    } 

しかし、列挙型準値とは、このようにrawValueを持つことはできません。自分で管理する必要があるかもしれません。 (実際には、それが実際のrawValueないですし

extension Dream.Creature: RawRepresentable { 
    var rawValue: Int { 
     switch self { 
     case .unicorn(let color): 
      return 0x0001_0000 + color.rawValue 
     case .crusty: 
      return 0x0002_0000 
     case .shark: 
      return 0x0003_0000 
     case .dragon: 
      return 0x0004_0000 
     } 
    } 

    init?(rawValue: Int) { 
     switch rawValue { 
     case 0x0001_0000...0x0001_FFFF: 
      if let color = UnicornColor(rawValue: rawValue & 0xFFFF) { 
       self = .unicorn(color) 
      } else { 
       return nil 
      } 
     case 0x0002_0000: 
      self = .crusty 
     case 0x0003_0000: 
      self = .shark 
     case 0x0004_0000: 
      self = .dragon 
     default: 
      return nil 
     } 
    } 
} 

enum Creature: Equatable { 
    enum UnicornColor: Int { 
     case yellow, pink, white 
    } 

    case unicorn(UnicornColor) 
    case crusty 
    case shark 
    case dragon 

    static func == (lhs: Creature, rhs: Creature) -> Bool { 
     //... 
    } 
} 

あなたにDream.Creatureの拡張子を書くことができます内側のenumのrawValueIntなどを持つ例えば

、より適切な名前に変更してください)

上記のような定義を使用すると、コードを利用することができます上記のリンクに示されています。

+0

ありがとうございました。 –

2

Swiftのネイティブ機能が常にObjective-Cでうまく機能しないため、発生する問題に対処しています。NSCodingはObjective-Cの世界に根を持ち、Objective-CはSwift Enumについて何も知らないので、単純にEnumをアーカイブすることはできません。

通常、生の値を使用して列挙をエンコード/デコードすることはできますが、見つかったように、関連付けられた型と生の値をSwift列挙に組み合わせることはできません。

残念ながら、これはあなたがあなた自身の「生の」値の方法を構築し、Creature列挙で明示的にケースを処理する必要があることを意味します

enum Creature { 

    enum UnicornColor: Int { 
     case yellow = 0, pink, white 
    } 

    case unicorn(UnicornColor) 
    case crusty 
    case shark 
    case dragon 

    init?(_ creatureType: Int, color: Int? = nil) { 
     switch creatureType { 
     case 0: 
      guard let rawColor = color, 
       let unicornColor = Creature.UnicornColor(rawValue:rawColor) else { 
        return nil 
      } 
      self = .unicorn(unicornColor) 
     case 1: 
      self = .crusty 

     case 2: 
      self = .shark 

     case 3: 
      self = .dragon 

     default: 
      return nil 
     } 
    } 

    func toRawValues() -> (creatureType:Int, unicornColor:Int?) { 
     switch self { 
     case .unicorn(let color): 
      let rawColor = color.rawValue 
      return(0,rawColor) 

     case .crusty: 
      return (1,nil) 

     case .shark: 
      return (2,nil) 

     case .dragon: 
      return (3,nil) 
     } 
    } 
} 

あなたは、このようにデコード/エンコードすることができます:

class SomeClass: NSObject, NSCoding { 

    var creature: Creature 

    init(_ creature: Creature) { 
     self.creature = creature 
    } 

    required init?(coder aDecoder: NSCoder) { 

     let creatureType = aDecoder.decodeInteger(forKey: "creatureType") 
     let unicornColor = aDecoder.decodeInteger(forKey: "unicornColor") 

     guard let creature = Creature(creatureType, color: unicornColor) else { 
      return nil 
     } 

     self.creature = creature 

     super.init() 
    } 

    func encode(with aCoder: NSCoder) { 
     let creatureValues = self.creature.toRawValues() 

     aCoder.encode(creatureValues.creatureType, forKey: "creatureType") 
     if let unicornColor = creatureValues.unicornColor { 
      aCoder.encode(unicornColor, forKey: "unicornColor") 
     } 

    } 
} 

テストができます:

let a = SomeClass(.unicorn(.pink)) 

var data = NSMutableData() 

let coder = NSKeyedArchiver(forWritingWith: data) 

a.encode(with: coder) 

coder.finishEncoding() 

let decoder = NSKeyedUnarchiver(forReadingWith: data as Data) 

if let b = SomeClass(coder: decoder) { 

    print(b.creature) 
} 

unicorn(Creature.UnicornColor.pink)

個人的に、私はあなたがDataを必要とするクリーチャーの初期化子とdataという名前の計算されたプロパティを提供することができデコード/コーディングを単純化するためにCreatureクラスを作成し、ユニコーンや他の種類の

+0

ありがとうございました! –

1

間の変化に対処するため、継承を使用します。クリーチャーが変更されたり新しい関連値が追加されると、NSCodingへのインターフェイスは変更されません。

class Foo: NSObject, NSCoding { 
    let creature: Creature 

    init(with creature: Creature = Creature.crusty) { 
    self.creature = creature 
    super.init() 
    } 

    required init?(coder aDecoder: NSCoder) { 
    guard let data = aDecoder.decodeObject(forKey: "creature") as? Data else { return nil } 
    guard let _creature = Creature(with: data) else { return nil } 
    self.creature = _creature 
    super.init() 
    } 

    func encode(with aCoder: NSCoder) { 
    aCoder.encode(creature.data, forKey: "creature") 
    } 
} 

生き物のシリアライゼーションへとDataのうち、このように達成することができます。

enum Creature { 
    enum UnicornColor { 
    case yellow, pink, white 
    } 

    case unicorn(UnicornColor) 
    case crusty 
    case shark 
    case dragon 

    enum Index { 
    static fileprivate let ofEnum = 0   // data[0] holds enum value 
    static fileprivate let ofUnicornColor = 1 // data[1] holds unicorn color 
    } 

    init?(with data: Data) { 
    switch data[Index.ofEnum] { 
    case 1: 
     switch data[Index.ofUnicornColor] { 
     case 1: self = .unicorn(.yellow) 
     case 2: self = .unicorn(.pink) 
     case 3: self = .unicorn(.white) 
     default: 
     return nil 
     } 
    case 2: self = .crusty 
    case 3: self = .shark 
    case 4: self = .dragon 
    default: 
     return nil 
    } 
    } 

    var data: Data { 
    var data = Data(count: 2) 
    // the initializer above zero fills data, therefore serialize values starting at 1 
    switch self { 
    case .unicorn(let color): 
     data[Index.ofEnum] = 1 
     switch color { 
     case .yellow: data[Index.ofUnicornColor] = 1 
     case .pink: data[Index.ofUnicornColor] = 2 
     case .white: data[Index.ofUnicornColor] = 3 
     } 
    case .crusty: data[Index.ofEnum] = 2 
    case .shark: data[Index.ofEnum] = 3 
    case .dragon: data[Index.ofEnum] = 4 
    } 
    return data 
    } 
} 

enter image description here

あなたの問題とは無関係の
+0

非常に良いオプション!ありがとう! –

関連する問題