Quand utiliser un type swift ou Foundation ?
Je viens de lire que, par exemple, les strings et arrays en Swift sont bridgés avec leurs homologues Cocoa si on appelle des méthodes Foundation dessus.
Ainsi on peut appeler capitalizedString sur une bête string swift... On n'a pas à convertir la string en NSString auparavant.
To enable string bridging, just import Foundation. For example, you can call capitalizedString"a method on the NSString class"on a Swift string, and Swift automatically bridges the Swift String to an NSStringobject and calls the method. The method even returns a Swift String type, because it was converted during import.
Idem pour les arrays.
Donc, j'ai l'impression que ça va être plus délicat de savoir quand utiliser NSArray ou [] selon les cas puisque les méthodes de Foundation sont accessibles "à la volée" ?
Et quid des performances ?
J'ai toujours lu que les tableaux en C étaient bien plus rapide que leurs homologues Cocoa. Et maintenant ? Quels sont les choix à faire ? Est-ce que le fait qu'il soient bridgés est gourmand en ressources ? Faut-il toujours utiliser un tableau swift en priorité si on n'a pas de méthodes de NSArray à appeler dessus ?
Réponses
Donc l'option tableau swift + for..in est à préférer à NSArray + NSEnumerator.
D'après ce que j'ai compris, si on applique une méthode de NSArray sur un [], le bridge n'est que momentané ? La méthode renvoie bien un tableau swift quand-même, qu'on pourrait donc passer dans une boucle, même s'il a été "bridgé" en NSArray à un instant T auparavant ?
OK merci.
Il y a tant de choses à savoir avant de convertir des classes, non pas que ça ne marcherait pas, mais pour essayer d'adopter les meilleurs "concepts" !
Je veux dire, le bridging fait des choses assez magiques. Si dans le Playground on tape "NSString" et qu'on fait un Pomme-clic dessus, on arrive dans le header de NSStringà· traduit à la volée par LLVM en une API Swift. Comme si NSString avait été réécrit en Swift (alors qu'Apple explique bien dans ses sessions que c'est juste traduit à la volée). Ce qui permet entre autres de voir les conversions de nommage qu'il fait en jartant les "With" et répartissant les arguments nommés ("-(id)initWithFormat:(NSString*)]" de NSString en ObjC devient "init(format: String)" en Swift par exemple).
Mais si on garde nos frameworks tierces (AFNetworking, FMDatabase, MagicalRecord, ...) en ObjC, on ne profitera pas des petits + de Swift.
- Par exemple, une fonction qui retourne un NSString* en Objective-C retournera toujours un "String!" en Swift (implicitly unwrapped optional) pour indiquer une String qui peut être nil (puisqu'en Obj-C les NSString étant des NSObject peuvent être nil) mais qui n'a pas à être unwrappée.
- Ou encore la méthode "-rangeOfString:" de NSString retournera toujours un Int!, qui j'imagine vaudra toujours la valeur équivalente à NSNotFound si la chaà®ne n'est pas trouvée (puisqu'ils n'ont pas changé l'implémentation de la méthode pour autant j'imagine) alors qu'en Swift on retournerait plutôt nil pour indiquer une valeur manquante (chose qu'on ne peut pas faire en ObjC pour un Int)
- Ou encore une méthode qui prendrait un NSArray en argument sous ObjC serait traduite en une API Swift qui prend un "AnyObject[]!" soit un tableau de "on sait pas quoi" " encapsulé dans un "implicitly unwrapped optional" encore une fois car ce NSArray peut être nil en ObjC. Alors qu'en Swift on aurait certainement un type plus spécifique genre "String[]?"
Bref c'est bien qu'il y ait le bridging ObjC -> Swift, mais comme ObjC n'a pas les Generics (avec les tableaux spécialisés, etc) ni les optionals pour les types Int, ni la possibilité d'indiquer si une méthode peut retourner nil ou retournera toujours un non-nil..., ces informations ne pourront pas transparaà®tre dans l'API traduite en Swift. "rangeOfString:" retournera toujours NSNotFound s'il ne trouve pas la chaà®ne. On devra typecaster les objets extraits d'un NSArray pour les utiliser, bref comme en ObjC.
Alors que si on porte nos APIs en Swift, on pourra rajouter toutes ces précisions dans nos APIs. On pourra faire des fonctions qui prennent spécifiquement des Int[] et pas des NSArray* contenant on ne sait pas trop quoi au juste, ou des fonctions qui retournent des "Int?". Tant qu'on ne portera pas nos APIs en Swift, on ne profitera pas de toute la richesse que Swift peut nous apporter dans sa possibilité de spécification plus fine du langage.
Merci pour ces précisions.
A terme, je pense que dans nos nouvelles classes Swift, on devrait beaucoup moins utiliser Foundation. Quand on voit la facilité avec laquelle ont peut modifier des tableaux en Swift, ça donne pas envie d'utiliser les méthodes "longues" d'obj-C qui faisaient ça avant.