Swift: les types et les casts

Swift, c'est objective-C sans le C... mais ça nous fait caster sans cesse !? ;)


C'est plus compliqué de choisir ses types et de faire des choix: rien que parce Int? peut être nil si on veut (avant j'avais tout en NSNumber).


 


1) Si on veut garder le Type Int natif de Swift sur la propriété, et utiliser NSNumber pour récupérer une valeur de la base:



var status:Int?

self.status = Int(dbRows.objectForColumnName("status") as NSNumber)

=> double cast


 


2) Si on veut garder le Type Int natif de Swift sur la propriété, et utiliser CInt pour récupérer une valeur:



var status:Int?
self.status = Int(dbRows.intForColumn("status") as CInt)

=> double cast


 


3) On décide d'utiliser CInt sur la propriété pour éviter le double Cast:



var status:CInt?
self.status = dbRows.intForColumn("status") as CInt

=> mais du coup on perd le type Int natif de Swift


 


4) Travailler uniquement avec NSNumber:



var status:NSNumber?
sself.status = dbRows.objectForColumnName("status") as NSNumber

=> mais du coup on perd le type Int natif de Swift


 


 


Tout ça pour pointer sur le fait que je dois double caster si je veux travailler avec Int... mais si on se met à  Swift, c'est quand-même pour utiliser les types natifs (Int, array...) au maximum non ?


 


Réponses

  • AliGatorAliGator Membre, Modérateur

    Swift, c'est objective-C sans le C... mais ça nous fait caster sans cesse !? ;)

    Va falloir un peu caster au début quand on va vouloir faire du bridging entre Swift et ObjC.

    Par contre si tu fais du pur Swift non t'auras pas souvent de cast.

    Et puis Swift et surtout le support de Swift dans LLVM est encore très jeune. Ca va vite évoluer tout ça.
  • muqaddarmuqaddar Administrateur
    juin 2014 modifié #3

    Il est conseillé quand-même d'utiliser les types natifs de Swift dès qu'on peut non, quitte à  avoir des double casts ? (car j'ai 4 choix possibles dans le premier post)


  • AliGatorAliGator Membre, Modérateur
    juin 2014 modifié #4
    Pour moi les 2 choix raisonnablement envisageables c'est de déclarer ta variable en :
    • Int? --> type natif de Swift, à  privilégier dans ton code en Swift. Si je ne m'abuse, il est bridgé avec le type "int" du C, comme String de Swift est bridgé avec le NSString d'ObjC
    • NSNumber --> type ObjC, utile uniquement à  mon sens si tu veux bcp t'interfacer avec de l'ObjC
    Je vois pas l'intérêt d'utiliser le type CInt. Ce type est là  pour des transitions plus bas niveau où on aurait des APIs C/ObjC qui seraient trop complexes d'auto-traduire en API Swift avec les types natifs équivalents.
    Quand tu as du NSString dans une méthode ObjC, LLVM te convertit directement ça en String dans l'API Swift. Normalement c'est pareil pour Int (et si le compilo n'arrive pas à  les bridger c'est que c'est sans doute un peu tôt pour faire mumuse et qu'il faut attendre la prochaine version de LLVM qui devrait corriger ce manquement).

    C'est un peu comme CVaListPtr ou des choses comme ça, ce sont des types obscurs qui sont apparus pour faire la transition C/Swift sous le capôt et contourner les problématiques de quand Swift a besoin de passer des paramètres là  qui sont des vrais pointeurs bas niveau pour du C, mais qui ont pour vocation de n'être utilisés que pour la transition et les implémentations internes sous le capot.
  • muqaddarmuqaddar Administrateur

    OK, je vais choisir Int? et le double cast.


     


    Par contre, toutes ces conversions Swift -> Obj-C, h'espère qu'elles ne bouffent pas trop les performances... (on verra quand j'enverrai mes grosses requêtes et pas un bête INSERT, et pour récupérer des milliers de record en types Swift.


  • AliGatorAliGator Membre, Modérateur
    Ah la la si tu t'étais mis à  CoreData plutôt que de faire du SQL à  la main... ^^
  • muqaddarmuqaddar Administrateur
    juin 2014 modifié #7


    Ah la la si tu t'étais mis à  CoreData plutôt que de faire du SQL à  la main... ^^




     


    J'aime faire du SQL à  la main. :-)


    Et crois-moi:


    - je pense que CoreData aurait été un calvaire pour certaines requêtes super compliquées sur 20 tables ou même que ça n'aurait pas été possible.


    - j'aime copier mes requêtes SQL pour la version Web en ruby... donc j'aurais dû les faire dans tous les cas (sauf à  faire du NoSQL évidemment)


  • AliGatorAliGator Membre, Modérateur
    juin 2014 modifié #8


    - je pense que CoreData aurait été un calvaire pour certaines requêtes super compliquées sur 20 tables ou même que ça n'aurait pas été possible.

    Oulà , on voit le gars qui n'a jamais pratiqué CoreData !!! ^^ C'est en général tout l'inverse au contraire.


    Du fait entre autres que CoreData est un Graphe Objet + qu'une BDD, ces requêtes sur 20 tables sont non seulement pas si compliquées mais en + super transparentes. Tu les utilises comme tu utilises des @property sur tes objets. "cellier.cave.vins" pour pointer sur les vins des caves de ton cellier par exemple, plutôt que d'avoir à  faire des "JOIN" de folie de partout comme tu es obligé de faire en SQL.


    En écrivant tes requêtes en SQL, tu dois avoir des requêtes de malade des fois qui font des jointures dans tous les sens ou doivent être assez compliquées je pense surtout si elles sont sur 20 tables. en CoreData, tu n'auras plus cette complexité.


    Exemple : Obtenir tous les celliers qui ont au moins un casier ayant au moins une bouteille dont la région du vignoble est celle recherchée (Désolé je ne m'y connais pas en vin j'ai peut-être sorti un cas d'usage qui est une grosse connerie ^^ mais tu vois l'idée)
    [cellar findAllWithPredicate:[NSPredicate predicateWithFormat:@ANY(cases.bottles.vineyard.region) == %@",region]];
    En SQL pur t'aurais eu à  faire des jointures entre tes tables cellar & cases puis entre cases & bottles puis entre bottles & vineyard puis entre vineyard & region tout ça avec des conditions de foud et une requête de 3km de long... Et après pour toi c'est CoreData le calvaire et pas SQL ? :D


    - j'aime copier mes requêtes SQL pour la version Web en ruby... donc j'aurais dû les faire dans tous les cas (sauf à  faire du NoSQL évidemment)

    Pourquoi tu n'utilises pas ActiveRecord pour ta version Web en Ruby ?! Là  aussi tu te prends le chou à  tout faire à  la main ^^

    En plus framework MagicalRecord sur iOS/OSX permet d'avoir un fonctionnement / design pattern très emprunté à  ActiveRecord donc tu pourrais avoir une API très similaire sinon identique entre iOS et Ruby !


    J'ai l'impression que tu n'as jamais utilisé d'ORM à  devoir encore tout faire à  la main avec des requêtes SQL de malade de 3km... tu dois bien galérer du coup !! Alors qu'avec un ORM ou ActiveRecord en Ruby et MagicalRecord/CoreData en iOS/OSX, tes requêtes/prédicats seraient tellement plus simples/compacts/lisibles (en Ruby comme en ObjC) !!
  • muqaddarmuqaddar Administrateur
    juin 2014 modifié #9


    Oulà , on voit le gars qui n'a jamais pratiqué CoreData !!! ^^ C'est en général tout l'inverse au contraire.


    Du fait entre autres que CoreData est un Graphe Objet + qu'une BDD, ces requêtes sur 20 tables sont non seulement pas si compliquées mais en + super transparentes. Tu les utilises comme tu utilises des @property sur tes objets. "cellier.cave.vins" pour pointer sur les vins des caves de ton cellier par exemple, plutôt que d'avoir à  faire des "JOIN" de folie de partout comme tu es obligé de faire en SQL.


    En écrivant tes requêtes en SQL, tu dois avoir des requêtes de malade des fois qui font des jointures dans tous les sens ou doivent être assez compliquées je pense surtout si elles sont sur 20 tables. en CoreData, tu n'auras plus cette complexité.




    Oui, j'ai des requêtes de malade mais au moins je maitrise le truc et la façon dont sont générées et optimisées les requêtes.

    Exemple : Obtenir tous les celliers qui ont au moins un casier ayant au moins une bouteille dont la région du vignoble est celle recherchée (Désolé je ne m'y connais pas en vin j'ai peut-être sorti un cas d'usage qui est une grosse connerie ^^ mais tu vois l'idée)

    [cellar findAllWithPredicate:[NSPredicate predicateWithFormat:@ANY(cases.bottles.vineyard.region) == %@",region]];
    En SQL pur t'aurais eu à  faire des jointures entre tes tables cellar & cases puis entre cases & bottles puis entre bottles & vineyard puis entre vineyard & region tout ça avec des conditions de foud et une requête de 3km de long... Et après pour toi c'est CoreData le calvaire et pas SQL ? :D



    C'est pas compliqué ça... 4 tables, pas de count... c'est bien loin de certaines de mes requêtes. ;)


    Pourquoi tu n'utilises pas ActiveRecord pour ta version Web en Ruby ?! Là  aussi tu te prends le chou à  tout faire à  la main ^^




    On voit que tu n'as jamais fait de requêtes super compliquées avec ActiveRecord !!

    J'utilise ActiveRecord partout pour des requêtes assez simples sur 3 ou 4 tables y compris avec quelques where, jointures, eager loading...


    Mais ça a ses limites, dès que tu veux additionner les critères, les comptages, les clauses...etc. Et là  tu utilises find_by_sql sinon t'es chocolat, crois-moi !


    Le problème c'est que 90% des applis ont 4 ou 5 tables en relation, c'est loin d'être mon cas. ;)
Connectez-vous ou Inscrivez-vous pour répondre.