web-dev-qa-db-fra.com

Comment puis-je encoder enum en utilisant NSCoder en swift?

Contexte

J'essaie d'encoder une énumération de style String à l'aide du protocole NSCoding, mais je rencontre des erreurs de conversion vers et depuis String.

J'obtiens les erreurs suivantes lors du décodage et de l'encodage:

La chaîne n'est pas convertible en scène

Argument supplémentaire ForKey: en appel

Code

    enum Stage : String
    {
        case DisplayAll    = "Display All"
        case HideQuarter   = "Hide Quarter"
        case HideHalf      = "Hide Half"
        case HideTwoThirds = "Hide Two Thirds"
        case HideAll       = "Hide All"
    }

    class AppState : NSCoding, NSObject
    {
        var idx   = 0
        var stage = Stage.DisplayAll

        override init() {}

        required init(coder aDecoder: NSCoder) {
            self.idx   = aDecoder.decodeIntegerForKey( "idx"   )
            self.stage = aDecoder.decodeObjectForKey(  "stage" ) as String    // ERROR
        }

        func encodeWithCoder(aCoder: NSCoder) {
            aCoder.encodeInteger( self.idx,             forKey:"idx"   )
            aCoder.encodeObject(  self.stage as String, forKey:"stage" )  // ERROR
        }

    // ...

    }
63
kfmfe04

Vous devez convertir l'énumération vers et depuis la valeur brute. Dans Swift 1.2 (Xcode 6.3), cela ressemblerait à ceci:

class AppState : NSObject, NSCoding
{
    var idx   = 0
    var stage = Stage.DisplayAll

    override init() {}

    required init(coder aDecoder: NSCoder) {
        self.idx   = aDecoder.decodeIntegerForKey( "idx" )
        self.stage = Stage(rawValue: (aDecoder.decodeObjectForKey( "stage" ) as! String)) ?? .DisplayAll
    }

    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeInteger( self.idx, forKey:"idx" )
        aCoder.encodeObject(  self.stage.rawValue, forKey:"stage" )
    }

    // ...

}

Swift 1.1 (Xcode 6.1), utilise as au lieu de as!:

    self.stage = Stage(rawValue: (aDecoder.decodeObjectForKey( "stage" ) as String)) ?? .DisplayAll

Swift 1.0 (Xcode 6.0) utilise toRaw() et fromRaw() comme ceci:

    self.stage = Stage.fromRaw(aDecoder.decodeObjectForKey( "stage" ) as String) ?? .DisplayAll

    aCoder.encodeObject( self.stage.toRaw(), forKey:"stage" )
67
vacawama

Mise à jour pour Xcode 6.3, Swift 1.2:

self.stage = Stage(rawValue: aDecoder.decodeObjectForKey("stage") as! String) ?? .DisplayAll

noter la as!

9
Adrian Sluyters

Voici une solution pour Swift 4.2. Comme indiqué dans les autres réponses, le problème est que vous essayez d'affecter directement la variable stage avec une chaîne décodée et que vous essayez de transtyper la variable stage en une chaîne dans la encodeWithCoder méthode. Vous devez utiliser valeurs brutes à la place.

enum Stage: String {
    case DisplayAll = "Display All"
    case HideQuarter = "Hide Quarter"
    case HideHalf = "Hide Half"
    case HideTwoThirds = "Hide Two Thirds"
    case HideAll = "Hide All"
}

class AppState: NSCoding, NSObject {
    var idx = 0
    var stage = Stage.DisplayAll

    override init() {}

    required init(coder aDecoder: NSCoder) {
        self.idx = aDecoder.decodeInteger(forKey: "idx")
        self.stage = Stage(rawValue: aDecoder.decodeObject(forKey: "stage") as String)
    }

    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encode(self.idx, forKey:"idx")
        aCoder.encode(self.stage.rawValue, forKey:"stage")
    }

    // ...

}
7
Jared Cleghorn