2017-04-20 6 views
1

私は私のクラスはNSCodingに準拠しようとしているが、その特性の一つは、このように、列挙型であるため、問題に実行しているよ:rawValueを持たないenumを(NSCodingで)エンコードするにはどうすればよいですか?

enum Direction { 
    case north 
    case south 
} 

列挙型は、コード可能なだったら、私はこのようにそれを行うことができます:

class MyClass: NSObject, NSCoding { 
    var direction: Direction! 
    required init(coder aDecoder: NSCoder) { 
     direction = aDecoder.decodeObject(forKey: "direction") as! Direction 
    } 
    func encode(with aCoder: NSCoder) { 
     aCoder.encode(direction, forKey: "direction") 
    } 
} 

しかし、列挙型では符号化できないため、encode()はエラーをスローします。

"How do I encode enum using NSCoder in swift?"の回答は、列挙型のrawValueのエンコードを示唆し、もう一方の端のrawValueからそれを初期化します。しかし、この場合、DirectionにはrawValueがありません!

これは有益と思われるhashValueを持っています。 hashValueを問題なくエンコードし、もう一方の端にあるIntにデコードし直すことができます。しかし、hashValueから列挙型を初期化する方法がないようですので、Directionに戻すことはできません。

値のない列挙型をエンコードおよびデコードするにはどうすればよいですか?

+0

ですから、生の値を追加するために列挙型を変更することはできません。しかし、あなたはEnumに他の変更を加えることができますか? – Sweeper

+0

@ Sweeper私はenumを変更することなくそれを行う方法を望んでいました。私は興味がありますが、rawValueを追加する以外にどのような変更が役に立ちますか? – Robert

+0

私はイニシャライザを追加することを考えていました – Sweeper

答えて

1

ここでは、列挙型に生の値を追加することは、コードが最も少ないソリューションであり、最もメンテナンス性が高いと思います。したがって、の場合はに列挙型を変更し、生の値を追加します。

ここで、列挙型を変更できないとします。それでもいくつかの方法でこれを行うことができます。

私はかなり醜いだと思う最初のものは、列挙型のextensionを追加し、このような静的メソッドを追加することです:

static func direction(from rawValue: String) -> Direction { 
    switch rawValue { 
     case: "north": return .north 
     case: "south": return .south 
     default: fatalError() 
    } 
} 

変換するために、String(describing:)を使用して、コード化可能値にDirectionを変換するには列挙型の列挙型です。文字列を列挙型に変換するには、上記の方法を使用してください。

もう少し良いですが、生の値を追加するだけではまだまだ良いものではありません。文字列に列挙型を変換するString(describing:)を使用して、コード化可能値にDirectionを変換するには

let enumValueDict: [String, Direction] = [ 
    "north": .north, "south": .south 
] 

あなたは辞書を使用しています。文字列を列挙型に変換するには、辞書にアクセスしてください。

1

いくつかのキーを定義して代わりに保存することができます。

fileprivate let kDirectionKeyNorth = 1 
fileprivate let kDirectionKeySouth = 2 

// ... 

required init(coder aDecoder: NSCoder) { 
    let key = aDecoder.decodeInteger(forKey: "direction") 
    switch key { 
     case kDirectionKeyNorth: 
    // ... 
    } 
} 

// and vise versa 

これはややこしい方法です。あなたはいつもDirectionのライブラリを見てください。新しい方向へのキーを追加します。

+0

私はこの権利を理解すれば、enumの各ケースに既知の値を割り当ててエンコーディングし、デコードされた値から新しいenumを手動で作成しますか? – Robert

+1

@Robert right!そして、 'switch'ステートメントは網羅的でなければならないので、新しい' Direction'ケースが現れたらコンパイル中に問題が発生します。 – Astoria

3

スウィフト4の新機能、enum エンコード可能です。ただし、生の値を持つ必要があります。あなたは簡単しかし、追加のコードを実行することができます。

enum Direction : String, Codable { 
    case north 
    case south 
} 

をNSCodingのMyClassクラスを使用してコード可能な列挙型の作業を行うには、このようなあなたのinit(coder:)encode(with:)実装:場合は、スウィフト4で

class MyClass: NSObject, NSCoding { 
    var direction: Direction! 
    required init(coder aDecoder: NSCoder) { 
     direction = (aDecoder as! NSKeyedUnarchiver).decodeDecodable(Direction.self, forKey: "direction") 
    } 
    func encode(with aCoder: NSCoder) { 
     try? (aCoder as! NSKeyedArchiver).encodeEncodable(direction, forKey: "direction") 
    } 
} 
0

:あなたの列挙型 Directionは生の値を持つことができ、あなたは NSCodingの代替として CodableDecodableEncodableプロトコル)を使用することができます

使用法:

import Foundation 

let encoder = JSONEncoder() 
let myClass = MyClass(direction: .north) 

if let data = try? encoder.encode(myClass), 
    let jsonString = String(data: data, encoding: .utf8) { 
    print(jsonString) 
} 

/* 
prints: 
{"direction":"north"} 
*/ 
import Foundation 

let jsonString = """ 
{ 
    "direction" : "south" 
} 
""" 

let jsonData = jsonString.data(using: .utf8)! 
let decoder = JSONDecoder() 
let myClassInstance = try! decoder.decode(MyClass.self, from: jsonData) 
dump(myClassInstance) 

/* 
prints: 
▿ __lldb_expr_319.MyClass #0 
    - direction: __lldb_expr_319.Direction.south 
*/ 
関連する問題