Il y a 5 ans, nous avions déjà écrit un article qui expliquait comment utiliser notre librairie dans un projet Swift. Malheureusement, durant ces 5 ans, Apple a fait évoluer ce langage de programmation et ce qui était valable à l'époque ne l'est plus forcément. Il est donc temps de remettre à jour cet article.
Depuis 2015, Swift est passé de la version 1.2 à la version 5.2. Durant cette période, plusieurs changements ont cassé la compatibilité ascendante. C'est-à-dire que du code Swift qui fonctionnait dans une version précédente devenait subitement faux.
De la même manière, l’intégration de code Objective-C dans un projet Swift a aussi changé et rendu notre précédent article obsolète. En effet, si vous utilisez une vielle version de notre librairie avec une version récente de Swift, l'application ne compile pas.
Heureusement, nous venons de publier un nouvelle version la librairie Objective-C qui s'intègre plus gracieusement avec Swift 5.x.
Qu'est ce qui a changé ?
Parmi les évolutions de Swift, deux changements majeurs posaient problèmes avec les précédentes versions de notre librairie.
Premièrement, le compilateur est devenu beaucoup plus strict avec l'utilisation des variables "optionnelles", c'est-à-dire des variables qui peuvent soit avoir une valeur, soit pointer sur nil. Par défaut, Swift 5 pense que toutes les fonctions Objective-C retournent une variable optionnelle et force le développeur à déballer ("unwrap" en anglais) la valeur. Nous avons modifié notre librairie Objective-C pour déclarer explicitement si les fonctions retournent un objet optionnel ou non. Désormais, lorsque vous utilisez notre librairie avec Swift, les types sont inférés correctement.
Deuxièmement, lors de l'importation des fichiers Objective-C, Xcode renomme les fonctions afin de suivre les conventions de nommage de Swift. L'idée de cette fonctionnalité est de raccourcir et rendre plus lisible les API iOS ou macOS écrites en Objective-C, qui étaient connues pour être très longues.
Ce renommage posait de gros problèmes avec notre librairie Objective-C. Non seulement, la documentation de notre librairie ne correspondait plus avec le code, mais certaines fonctions étaient simplement ignorées ou mal converties. Par exemple, les méthodes nextFunction(), nextModule ou nextSensor se retrouvaient toutes renommées en next(), ce qui causait un conflit lors de la compilation. Heureusement, Apple a récemment ajouté la possibilité de spécifier dans le code Objective-C le nom que la fonction doit avoir en Swift. Grâce à cela, les méthodes ont désormais le même nom en Swift qu'en Objective-C.
Nouvelle version de la librairie Objective-C
Afin de résoudre les problèmes que nous venons de discuter, nous avons publié une nouvelle version de la librairie Objective-C: la version 1.10.41779.
Pour les applications qui sont toujours écrites en Objective-C, notre nouvelle libraire est 100% backward compatible. Si le code de votre application est écrit en Objective-C, vous pouvez mettre à jour notre librairie Yoctopuce sans modifier votre code.
Si vous utilisez Swift, c'est différent. Il faudra très probablement modifier quelques parties de votre code. Mais la plupart du temps, le code deviendra plus simple car il n'y aura plus besoin de tester si les valeurs retournée par l'API sont nulles ou pas.
Un exemple d'utilisation de notre librairie avec Swift 5.2
Pour finir, nous allons reprendre notre article et voir comment utiliser notre librairie Objective-C dans un projet Swift 5.2.
Comment inclure la librairie Objective-C dans un projet Swift ?
Cette partie n'a pas changé, il faut toujours ajouter les fichiers .m et .h ainsi que le sous-répertoire yapi au projet Xcode et créer un "bridging header". Le plus simple est de glisser-déposer tous les fichiers du répertoire Sources de la librairie Objective-C directement dans le Navigateur de projet Xcode. Xcode lance un assistant qui ajoute ces fichiers au projet et crée un "bridging header" qui sera utilisé par les fichiers Swift.
Selectionnez 'add to targets' quand Xcode import les fichiers, sinon vos fichiers ne seront pas compilés
Quelques petites remarques :
- N'oubliez pas de sélectionner votre application dans le champ "add to target" de cet assistant, sinon Xcode ajoute les fichiers au projet mais ne les compile pas.
- Sélectionnez "Yes" quand Xcode vous propose de créer le "Bridging header" sinon les fichiers sont compilés mais inutilisables dans votre fichier Swift.
- Sélectionnez tous les fichiers du répertoire Source et non le répertoire Source, sinon Xcode ne propose pas de créer le "Bridging header".
La deuxième étape est d'inclure les headers des fichiers Objective-C nécessaires dans le bridging header. Par exemple, si l'on veut utiliser un Yocto-Meteo dans un programme Swift, il faut inclure les fichiers yocto_api.h, yocto_humidity.h, yocto_temperature.h et yocto_pressure.h.
// Use this file to import your target's public headers that
// you would like to expose to Swift.
//
#import "yocto_api.h"
#import "yocto_humidity.h"
#import "yocto_temperature.h"
#import "yocto_pressure.h"
Si tout s'est bien passé, Xcode compile sans erreur tous les fichiers Swift, les fichiers Objective-C et les quelques fichiers C.
Utiliser la libraire Yoctopuce en Swift
Maintenant que les fichiers Objective-C sont compilés, il faut écrire le code Swift qui utilise la librairie Yoctopuce. Nous allons traduire l'exemple "Doc-Inventory" en Swift. Les explications sur ce que fait cet exemple sont données dans la documentation de notre librairie Objective-C et dans la documentation de tous les modules Yoctopuce.
var error: NSError?
// Sets up the API to use local USB devices
var res = YAPI.RegisterHub("usb", &error)
if res.rawValue != YAPI_SUCCESS.rawValue {
print("Error: \(error!.localizedDescription)")
exit(0)
}
print("Device list:")
var optional_module = YModule.FirstModule()
while let module = optional_module {
let serial = module.get_serialNumber()
let productName = module.get_productName()
print("\(serial) \(productName)")
optional_module = module.nextModule()
}
YAPI.FreeAPI()
Comme on peut le voir, les méthodes ont le même nom et les mêmes paramètres qu'en Objetive-C. La syntaxe est désormais cohérente avec la documentation de notre API.
On peut aussi voir que seules les variables qui en ont besoin sont définies comme "optionnelles". Par exemple, les variables error et optional_module peuvent effectivement être à nil et il faut donc les déballer ("unwrap" en anglais) à l'aide du caractère ! ou ?. Au contraire, les valeurs retournées par get_serialNumber() ou get_productName() peuvent être utilisées directement car elles seront toujours valides.
Le code de l'exemple
Cet exemple est disponible dans l'archive de notre librairie Objective-C. Il se trouve dans le sous-répertoire Examples/Prog-UseWithSwift52. La librairie est téléchargeable sur notre site Web ou sur GitHub.