Mixer Obj-C et Swift
LeChatNoir
Membre, Modérateur
Bon, j'ai toujours pas le temps d'apprendre le swift mais vu que je vais commencer un nouveau module, je me demande si je m'y mettrai pas...
Donc ma question est simple. Je charge mes VC (ViewController) à l'ancienne depuis des xib...
Depuis un VC objective-C, est ce que je peux instancier et "pusher" un VC écrit en swift... ?
Si oui, comment ?
Si non, je suis prêt à utiliser Storyboard comme il se doit mais même dans ce cas, je vais devoir passer des variables à mon nouveau VC dans le prepareForSegue et donc, comment le faire ?
Merci !
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
ObjC et Swift sont interopérables à 100%. Swift supporte 100% des API existantes en ObjC. Donc Oui, tu peux charger les view controllers écrits en Swift à partir de VC écrits en ObjC, et inversement. Et ils peuvent toujours manipuler des xib.
Xcode génèrera automatiquement un header ObjC correspondant à la classe du VC écrit en Swift.
Ok. J'ai effectivement trouver des choses en ce sens... Par contre, depuis Swift 2, ça a l'air différent.
J'ai ma classe swift qui doit déclarer qu'elle est compatible obj-C via @objc.
Or avec swift 2, visiblement, c'est forcément une classe qui hérite de NSObject.
Donc quand je veux déclarer ma classe Swift en faisant :
Je me prend une erreur compilo qui dit :
"Only classes that inherit from NSObject can be declared @objc"
Du coup, je fais comment ?
Oups... Ok, j'avais pas tout lu... Il me dit dans un même temps qu'il ne connait pas UIViewController...
Donc un simple import résout le pb...
Je continue la découverte... Et merci Zoc pour tes encouragements
Ok, donc voilà les étapes à dérouler :
1 - créer sa classe Swift (un seul fichier, plus de .h, perturbant pour un vieux comme moi )
2 - cette classe doit contenir la directive @objc pour pouvoir être utilisée depuis une classe objective-C
3 - le type doit hériter de NSObject. Si c'est un objet provenant d'UIKit, bien importer UIKit
4 - dans sa classe objective-C, on peut alors instancier son objet :
5 - on va avoir alors une erreur indiquant qu'il connait pas cette classe. Il faut vérifier les paramètres suivants dans les build settings de sa target :
Et importer un header magique dans le .m où on veut utiliser la classe swift. Ce header magique, on va trouver son nom dans les build settings aussi à la rubrique "Objective-C Generated Interface Header Name"
Un petit clean & rebuild et ça fonctionne
Etape 0: Faire attention aux nommages de toutes tes classes swift parce que dans ce cas tu vas retomber dans l'espace de nommage Objective-C pour toutes tes classes swift et pas seulement celles que tu utilises en Objective-C.
En tous cas moi, je n'ai pas trouvé de moyen d'exclure des classes swift du "header magique".
à‰tape 2 n'est pas nécessaire si la classe dérive d'une classe qui dérive elle-même de NSObject.
Tu aurais pu créer un fichier dans Xcode en cliquant sur File | New | File... , choisissant Cocoa Touch Class - Next - Subclass... UIViewController - Language: Swift - et diff, paf, pouf, ça y est ! Même avec le import UIKit déjà là 8--)
Et, comme dit FKDEV, ne mets pas les préfixes avant les noms des classes en Swift ; c'est pas nécessaire parce que tous les type Swift appartient du namespace du mode où ils se trouvent. Dans le cas d'un projet MonApp, le type Swift ViewController serait nommé, selon le compilateur, MonApp.ViewController
Tout à fait. En fait, j'avais timidement créé un "single swift file" + une UI...
Effectivement, en passant par CocoaTouch, c'est mieux
Pour les préfixes, je ne comprens pas trop ce que vous dites... ???
La raison qu'il nous fallait mettre les préfixes avant les noms des types était pour éviter les conflits entre nos propres types et ceux des types d'autres APIs.
En Swift, tous les types sont automatiquement fait partie du module où ils sont écrits. Du coup, c'est pas nécessaire pour toi d'utiliser CA comme préfixe , car le nom sera déjà préfixé avec (e.g.) MyLibrary ou MyApp.
Si quelqu'un écrivait un type avec le même nom, il serait préfixé par TheirLibrary ou TheirApp.
Je viens de faire les expériences avec les types qui représentent les mesures et les unités de mesure. Or, il existe déjà les types similaires avec les mêmes noms dans le framework Foundation. Pour éviter les conflits de noms, il ne faut qu'écrire mes types comme :
En fait j'ai dit le contraire.
C'est vrai que dans Swift, on n'a plus besoin de préfixer les nom de classes.
Mais, d'après mon expérience, quand on utilise une classe swift en Objective-C on retombe dans le problème.
Par exemple dans un projet swift j'ai créée une classe nommé MusicTrack.
Puis un jour, j'ai voulu utiliser une classe objective-C alors j'ai suivi la même procédure que celle décrite par LeChatNoir.
Et là je me suis retrouvé avec un conflit de nom avec la classe MusicTrack définie dans le framework Apple "AudioToolbox".
Bon, comme je suis un vieux briscard, j'ai trouvé le contournement suivant :
Mais je ne sais pas s'il y a une meilleure solution.
As tu tenté de changer le nom de la classe vu par Objective C avec la directive @objc ?
Non car je ne connaissais pas cette méthode (pourtant j'ai cherché sur stackoverflow).
Par contre, cette classe est également utilisée dans realm et cela semble poser problème à Realm si j'utilise cette méthode.
C'est peut-être juste une migration de schema à faire mais comme cette classe est également utilisée dans des relations avec d'autres classes (playlist), je préfère ne pas rentrer là -dedans.
Bon ben voilà , je me retrouve avec les questions de base de noob....
Comment je fais ça en swift ?
Simple... Thank you
Bon... Je galère pas mal avec les types... Moi qui croyais que c'était plus simple en Swift...
J'ai un tableau de dictionnaires issu de JSON. Seulement parfois j'ai en value des NSStrings, parfois des NSNumber.
Donc en Swift, je voudrais bien lui dire :
ben non... J'ai aussi des String:String...
Et y a un truc dingue aussi.
Si je mets :
S'il y a un lien avec Objective C alors il vaut mieux (faut ?) utiliser AnyObject plutôt que Any qui permet de représenter en Swift plus que des instances d'objets.
Si tu utilises NSDictionary en Objective-C, il faut utiliser [NSObject: AnyObject] en Swift.
En plus, avec les nouveaux types génériques en Objective-C, tu pourrait utiliser NSDictionary<NSString *, NSObject *> *toto; pour mieux gérer les clés.
Mes datas sont du JSON qui provient d'un webservice.
En fait, j'ai réussi à le faireavec AnyObject effectivement et en considérant que mes chiffres étaient des strings.
Ca donne ça :
Ca le fait.
Merci à vous 2 pour votre aide précieuse !
C'est chaud le swift
Ta dernière ligne force à croire que element ne sera pas nil et qu'il peut donc accéder à la propriété floatValue or tu n'en sais rien. C'est une mauvaise pratique en Swift. Tu dois tester ton element à l'aide d'une condition ou d'un guard afin de l'utiliser avec l'assurance qu'il est bien un String.
Puis :
Ou même un protocole qui renvoie directement un CGFloat.
J'ai pu finaliser mon 1er view contrôleur swift
Merci à vous !
Tu ne veux pas nous le montrer ?
Je donne mon avis un peu tard mais c'est pas la meilleure idée de produire du code Swift 2.x pour le moment...
Une fois la 3 releaseÌe tu pourras (presque) tout recommencer et réapprendre à penser Swift. L'inter-opeÌration entre Swift et Obj-C est différente dans Swift 3 et vu les SE proposées et accepteÌes ça va encore changer.
Exit AnyObject pour les types Obj-C, bonjour Any ! Les NSDictionnary typent <AnyHashable : Any>. Ce genre de choses... Donc soit tu attends la release soit tu passe à la 3 beta et tu vas t'amuser à chaque beta d'Xcode à réadapter ton code.
Bref c'est pas le bon moment pour commencer Swift.
Oui. Seulement, je finalise encore un truc et je rencontre à nouveau des difficultés
J'ai un tableau défini comme suit :
ça passe bien...