Les NSValueTransformers et Swift, quelqu'un a testé ?
Je voudrais utiliser un NSValueTransformer dans un petit projet en Swift.
Le tranformer en question doit prendre un numéro en entrée (entre 0 et 11) et me retourner un NSString avec le nom du mois (indexé à partir de zéro).
Comme je n'ai pour ainsi dire trouvé aucun exemple sur le net en swift, j'ai transposé les exemples en objective-C (je précise que je n'ai jamais manipulé de NSValueTransformer dans aucun des deux langages jusqu'à aujourd'hui).
Bref, je l'ai déclaré comme ceci :
class MoisTransformer: NSValueTransformer {
override class func transformedValueClass() -> AnyClass!
{
return NSString.self
}
override func transformedValue(value: AnyObject!) -> AnyObject!
{
var nomDuMois:NSString = "";
(--- je vous épargne le switch sur les douze mois, l'essentiel ici, c'est que ça compile bien ---)
return nomDuMois
}
}
Puis je l'ai enregistré dans le App Delegate comme ceci :
let leNomDuMois:MoisTransformer = MoisTransformer()
func applicationDidFinishLaunching(aNotification: NSNotification?) {
// Insert code here to initialize your application
NSValueTransformer.setValueTransformer(leNomDuMois, forName:"MoisTransformer")
}
Or quand j'essaye de l'appliquer sur un Text Field (via l'Interface Builder), j'ai cette erreur à l'exécution :
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Cannot find value transformer with name MoisTransformer'
Est-ce que ça ne fonctionne pas encore, ou bien c'est moi qui ai raté une marche ?
Om Nom
Réponses
Au hasard : le XIB ne serait-il pas chargé avant l'appel de applicationDidFinishLaunching, et donc avant l'appel à setValueTransformer ?
Parce que moi de ce que je lis, il est conseillé d'appeler setValueTransformer dans la méthode (de classe) "+initialize" de la classe du dérivé de NSValueTransformer, ou, d'après le "Value Transformer Programming Guide" :
Merci de ces infos, c'est sans doute là que réside le problème.
En fait, si j'ai opté pour applicationDidFinishLaunching c'est parce que je n'ai pas trouvé de méthode appelée plus tôt dans mes classes Swift, donc j'ai fait confiance, sans doute un peu trop vite, au commentaire : // Insert code here to initialize your application
Reste que je ne trouve pas d'équivalent au initialize dans les classes Swift...
Peux-tu m'en dire plus sur une façon d'appeler setValueTransformer depuis la méthode de classe dérivée MoisTransformer ? Je ne sais pas quoi passer en premier paramètre : c'est supposé être une instance de NSValueTransformer, mais impossible d'utiliser self puisque je suis dans une méthode de classe.
Il n'y a pas d'équivalent effectivement, mais comme ton délégué d'application est dérivé d'une classe "Objective-C" tu peux mettre ta propre implémentation dans une fonction
Argh... j'ai trouvé ! C'est moi qui ai fait mon gros boulet !
En fait, il manquait juste
@objc(MoisTransformer)
avant la déclaration de ma classe...
Du coup, petit bilan :
A l'heure actuelle, si on le déclare dans applicationDidFinishLaunching, ça fonctionne contre toute attente. Mais étant donné le paragraphe du programming guide que soc a cité, c'est plus raisonnable de suivre les préconisations et de l'intégrer dans la méthode initialize de l'app delegate (merci à jpimbert).
Deux petites précisions complémentaire (pour ceux qui cherchent à faire la même chose que moi). Comme il s'agit d'un override, il faut ajouter le mot-clé en Swift :
class override func initialize() {
et comme il s'agit d'une méthode de classe, l'instance du transformer ne peut pas être un attribut de la classe App Delegate car (à l'heure actuelle, en tous cas) un attribut static en swift ne peut pas être une classe !
Il faut donc déclarer l'instance du transformer hors de la classe (c'est moche mais ça marche).
En tous cas, merci à tous de votre aide !
Om Nom
Ca ne devrait même pas être nécessaire car ta classe dérive d'une classe Objective-C, et donc c'est implicite (ou alors ça a changé à un moment donné au fil des bêtas et j'ai raté l'info...).
C'est expliqué dans la doc de la méthode "valueTransformerForName:" en fait : " If valueTransformerForName: does not find a registered transformer instance for name, it will attempt to find a class with the specified name. If a corresponding class is found an instance will be created and initialized using its init: method and then automatically registered with name. "
Pour fonctionner à ce jour sur xCode 6.4 et sur Swift il faut transformer le code en
Effectivement dans Interface Builder ça marche tout de suite !! Les changements ? & ! sont subtiles
Par contre l'exemple donné ne me semble pas très intéressant. En effet je me suis cassé les dents sur les problèmes de date. Pour trouver le nom d'un mois dans une date, mieux faut se pencher sur NSDate et NSDateFormatter. Un bon casse tête mais qui permet d'avoir une version internationale tout de suite. Il n'est pas toujours facile de trouver la meilleure solution à un problème au vu du nombre incalculable de classes disponible dans Cococa & co.
Personnellement je me suis servi de NSValueTransformer pour transformer la valeur d'une note midi sous forme d'entier en une valeur sous forme de String. C'est tout simple les notes vont de 0 à 127, il y a 12 notes par octaves et une convention qui établis la valeur de l'octave de départ à -2. Ainsi 1 donne C-2 ; 60 donne C3 ; 127 donne G8 etc.
Comme ce site m'aide pour chacun de mes développements, voici le code que je vous offre.
Tous les commentaires sont les bienvenus...
Note aux admins : Je galère à publier du code en swift correctement dans un message sur le forum
Si j'édite ton message d'origine je vois qu'il ressemble à ceci :
En effet comme tu le soulèves iLandes, Et je ne peux qu'appuyer cette remarque.
C'est une mauvaise idée de lister soi-même les noms des mois, alors que NSDateFormatter et NSLocale non seulement savent déjà faire ça pour toi, mais en plus le font bien mieux, en gérant déjà toutes les langues, les cas particuliers auxquels tu n'as sans doute pas pensé (quid des cas dans différents fuseaux horaires quand es sur une date qui en France correspond à 1h30 le 1er Août mais correspond encore à la date du 31 Juillet aux US, quid des gens (rares, certes, mais ils existent) qui n'utilisent pas le calendrier Grégorien " genre calendrier chinois ? etc...), le contexte, et les différentes formes (courtes, longues, etc)...