Ceci est ma classe générique:

open class SMState<T: Hashable>: NSObject, NSCoding {
    open var value: T

    open var didEnter: ( (_ state: SMState<T>) -> Void)?
    open var didExit:  ( (_ state: SMState<T>) -> Void)?

    public init(_ value: T) {
        self.value = value
    }

    convenience required public init(coder decoder: NSCoder) {
        let value = decoder.decodeObject(forKey: "value") as! T

        self.init(value)
    }

    public func encode(with aCoder: NSCoder) {
        aCoder.encode(value, forKey: "value")
    }
}

Ensuite, je veux faire ceci:

    let stateEncodeData = NSKeyedArchiver.archivedData(withRootObject: currentState)
    UserDefaults.standard.set(stateEncodeData, forKey: "state")

Dans mon cas, currentState est de type SMState<SomeEnum>.

Mais quand j'appelle NSKeyedArchiver.archivedData, Xcode (9 beta 5) affiche un message en violet disant:

Attempting to archive generic Swift class 'StepUp.SMState<StepUp.RoutineViewController.RoutineState>' with mangled runtime name '_TtGC6StepUp7SMStateOCS_21RoutineViewController12RoutineState_'. Runtime names for generic classes are unstable and may change in the future, leading to non-decodable data.

Je ne sais pas exactement ce qu'il essaie de dire. N'est-il pas possible d'enregistrer un objet générique?

Existe-t-il un autre moyen d'enregistrer un objet personnalisé générique?

edit:

Même si j'utilise AnyHashable au lieu de génériques, j'obtiens la même erreur lors de l'exécution en appelant NSKeyedArchiver.archivedData:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: : unrecognized selector sent to instance
3
Adrian 18 août 2017 à 11:17

2 réponses

open class SMState: NSObject, NSCoding {
    open var value: AnyHashable

    open var didEnter: ( (_ state: SMState) -> Void)?
    open var didExit:  ( (_ state: SMState) -> Void)?

    public init(_ value: AnyHashable) {
        self.value = value
    }

    convenience required public init(coder decoder: NSCoder) {
        let value = decoder.decodeObject(forKey: "value") as! AnyHashable

        self.init(value)
    }

    public func encode(with aCoder: NSCoder) {
        aCoder.encode(value, forKey: "value")
    }
}

Maintenant, cette classe SMState est comme SMState<T: Hashable>, vous pouvez envoyer n'importe quel type d'énumération dans cette classe SMState.

Ensuite, vous pouvez utiliser cette classe SMState comme vous le souhaitez sans le générique

enum A_ENUM_KEY {
    case KEY_1
    case KEY_2
} 

let stateEncodeData = NSKeyedArchiver.archivedData(withRootObject: currentState)
UserDefaults.standard.set(stateEncodeData, forKey: "state")

Dans ce cas, currentState est de type SMState et SMState.value est SomeEnum, car Any Enums est AnyHashable

0
pluto 18 août 2017 à 15:18

Pour adresser "NSInvalidArgumentException ', raison:: sélecteur non reconnu envoyé à l'instance", assurez-vous que la superclasse de la classe que vous essayez d'archiver étend également NSCoder.

0
Zack 1 nov. 2017 à 01:52