NSCoder et les enums Swift
Joanna Carter
Membre, Modérateur
Je viens de jouer avec le restorableState d'un UIViewController et je voulais sauvegarder un enum Swift.
"C'est pas possible" je vous entends crier.
Mais si !
extension NSCoder
{
func encode<EnumType: RawRepresentable>(_ enumValue: EnumType, forKey key: String)
{
encode(enumValue.rawValue, forKey:key)
}
func decodeEnum<EnumType : RawRepresentable>(forKey key: String) -> EnumType?
{
if let rawValue = decodeObject(forKey: key) as? EnumType.RawValue
{
return EnumType.init(rawValue: rawValue)
}
return nil
}
}
Et pour l'utiliser :
enum Index : Int
{
case zero = 0
case une
case deux
}
class ViewController : UIViewController
{
var index: Index = zero
override func encodeRestorableState(with coder: NSCoder)
{
super.encodeRestorableState(with: coder)
coder.encode(self.index, forKey: "Index")
}
override func decodeRestorableState(with coder: NSCoder)
{
super.decodeRestorableState(with: coder)
guard let index = coder.decodeEnum(forKey: "Index") as Index? else
{
return
}
...
}
}
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
NSCoding est super pour sauvegarder des données, mais à partir d'une classe dont c'est le rôle. Perso, je fais dériver cette classe directement de NSObject. Ensuite, tu peux updater autant que tu veux, et pour peu que tu aies donné des valeurs par défaut à ta classe, tu peux ajouter des nouvelles valeurs à tes anciennes archives sans problème. De ce fait, le fonctionnement en arborescence de NSCoding surclasse totalement la sérialisation. Pourquoi donc veux-tu régresser vers la sérialisation? (le terme n'est pas trop fort me semble t-il...)
Logiquement, tu devrais avoir une classe indépendante de ta UIViewController dont le travail est, justement de "NSKeyArchiver" des "NSCodées" valeurs ou instances de classe, ou tout ce que tu veux (sans oublier les NSCodées de classes NSCodées de classes...)
C'est pas une question de sauvegarder l'état de n'importe quel objet. Ce que je fais, c'est une partie du mécanisme de State Preservation d'un ViewController (https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/PreservingandRestoringState.html).
Les deux méthodes : encodeRestorableState et decodeRestorableState, sont invoqués par le système chaque fois que l'app soit mis en arrière-plan et réveillé. Du coup, l'utilisateur trouvera l'app dans le même état où il l'a quitté, au lieu de le recommencer.
J'aurais pu sauvegarder le rawValue de l'enum mais j'ai voulu déterminer s'il serait possible de sauvegarder les enums et, voilà , c'est bien possible, si on utilise l'extension de NSCoder que j'ai rédigé.
D'une manière comme d'une autre il est grand temps qu'ils permettent le bridging entre Swift et Objective-C. Mais il va falloir attendre Swift 4...
Un peu de lecture sur le sujet
Je suis d'accord et j'ai déjà fait des expériences avec le protocole _ObjectiveCBridgeable. ça marche très bien mais ils ont décidé de le laisser privé, bien qu'il est accessible.
Mais dans le cas d'un enum, c'est assez compliqué de faire une classe Objective-C qui pourrait représenter les enums sophistiqué que l'on trouve en Swift.
NSData. J'avais fait des tests et tu pouvais passer un enum en dumpant directement dans la meÌmoire avec des pointeurs mais ça remonte...
Et _ObjectiveCBridgeable n'est pas fonctionnel. J'ai testeÌ dans CoreGeometry ça marche pas.