Faire une liste avec une TableView ou pas ?

Bonjour à  toutes et à  tous,

J'aimerais faire une liste comme celle du fichier joint. Les dates à  gauche changent avec les jours et les numéros à  côté des ronds blanc et noire augments en cliquant sur des butons.

Je ne sais pas si on peut faire cela avec une UITableView ou bien si je dois le faire qu'avec des UILabel et des UIImage? ???

Merci d'avance pour vos réponses! ::)


Réponses

  • UITableView avec UITableViewCell customisée je dirais...


  • OK...j'essai!!



    Merci beaucoup!  ::)


  • Voilà , c'est fait!

    Pour ceux que ça intéresse, voici xcodeproj: http://ovh.to/ReUUStC

    Etant débutant, les commentaires sont les biens venus!




     


    Merci @+


  • LarmeLarme Membre
    novembre 2013 modifié #6

    J'ai regardé vite fait, mais tu pourrais pas simplifier tableView:cellAtIndexPath ?

    D'ailleurs, tu fais des if enchaà®nés, et tu devrais plutôt utiliser des else if, car si tu rentres dans l'un, tu ne rentreras pas dans l'autre, et en plus tu évites des tests (quand c'est le indexPath row = 0 par exemple). Mais dans ton cas particulier, un switch serait encore mieux.


    Essaye de mettre ton NSDateFormatter en propiété, car ses init sont très gourmandes en ressources, et tu perds donc en vitesse.


  • OK merci!





  • Essaye de mettre ton NSDateFormatter en propiété, car ses init sont très gourmandes en ressources, et tu perds donc en vitesse.




     


    Voilà  mon .h


     


    /...


    @property (strong, nonatomic) NSDateFormatter *dateFormatter;

     


    et mon .m


     


    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

    {


    NSInteger row = [indexPath row];

        _dateFormatter = [[NSDateFormatter alloc] init];


        NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];

        NSDate *newDate;

        [_dateFormatter setDateFormat:@MM.dd.yyyy];

        NSString *formattedDateString;

        

        UIImage *rowBackground;

        cell.backgroundView = [[UIImageView alloc] init];

        

        switch (row) {

                

            case 0:

                

                [offsetComponents setDay:-6];

                newDate = [[NSCalendar currentCalendar] dateByAddingComponents:offsetComponents toDate:gbgDataCell.date options:0];

                formattedDateString = [_dateFormatter stringFromDate:newDate];

                

                cell.dateLabel.text = formattedDateString;

                cell.numStoneWhiteLabel.text = gbgDataCell.numStoneWhite;

                cell.numStoneBlackLabel.text = gbgDataCell.numStoneBlack;

                cell.stoneWhiteImage.image = [UIImage imageNamed:gbgDataCell.stoneWhite];

                cell.stoneBlackImage.image = [UIImage imageNamed:gbgDataCell.stoneBlack];

                

                rowBackground = [UIImage imageNamed:@backgroundColor1.png];

                

                break;

                

            case 1:

     

  • Il me semble que c'est surtout le combo alloc/init du NSDateFormatter qui est gourmand en temps...

    Comme de plus tu utilises toujours le même format, tu peux faire tout ça bien avant.


     


    Les ronds blancs/noirs, c'est pas toujours les mêmes quelque soit le cas ? Si c'est ça, autant les sortit du switch.


  • AliGatorAliGator Membre, Modérateur
    Je plussoie, le alloc/init d'un NSDateFormatter est très gourmand ; y'a même une technote Apple sur le sujet expliquant les techniques pour optimiser leur usage.

    Grosse perte d'optimisation que de le alloc/init à  chaque fois dans cellForRowAtIndexPath d'autant qu'à  chaque fois c'est pour l'initialiser avec la même chose et le même format,
  • LarmeLarme Membre
    novembre 2013 modifié #11

    Bon, avec un peu plus de recul...


     


    - Dans GBGCell, tu pourrais ajouter une méthode qui prendrait en paramètre un GCGData et remplirait la cell automatiquement (sauf la date apparemment, et encore, si tu rajoutes quelques trucs de calculs dessus, tu pourrais directement lui envoyer le NSString qui va bien en paramètre).

    Example :



    -(GBGCell)fillWithGCGData:(GCGData*)data andWithStringDate:(NSDate*)stringDate
    {
       [dateLabel setText:stringDate];
       [numberStoneWhiteLabel setText: [data numStoneWhite]];
    }

    Je sais que c'est encore du tâtonnement, et ne connaissant pas le projet, j'ai du mal à  voir ce qui est statique, mais as-tu besoin de remplir les points noirs et blancs à  chaque fois, où ils peuvent être fait dans sans à  avoir à  rentrer ces données dans GCGData ?

    En bref, il serait intéressant d'éviter d'avoir autant de duplication de code...


    Rien que là  : le offsetComponent devrait pouvoir se faire avec une p'tite formule (et ainsi supprimer des lignes de codes relativement identiques). J'ai pas tout vérifier tous les cas, mais du row-6, ça donne pas ça ?


     


    Sur le rowBackground et le nom de l'image, tu pourrais aussi faire un [UIImage imageNamed:[NSString stringWithFormat:@%backgroundColor%d.pn, row+1]].


    Donc faudrait peut-être donné en paramètre supplémentaire d'exemple précédent, le row qui permettrait ainsi de setter à  la voler le background et le component offset, ou tu le fais au même endroit, mais en dehors du switch.


    Pareil, le setting des fonts pourrait se faire dans le GBGCell, voire totalement dans le .xib vu que y'en a un...

    Pour tes stones (rond noirs/blancs), c'est pas plus simple de le remplir également dans le .xib de la cell ?


     


    J'ai regardé vite fait, et avec un oe“il extérieur (c'est toujours facile de critiquer surtout quand ce n'est pas son travail), et je connais pas le réel avancement de la chose (entre bidouilles/tests et avancement), mais bon, y'a quelques trucs à  simplifier/factoriser.

     


  • Suber, je vais voir tout ça et je vous rédis.


     



  • Voilà  la nouvelle version en fichier attaché! :D


     


    Merci Larme pour ces précieux conseilles!! ::)


     


    Larm: "Pareil, le setting des fonts pourrait se faire dans le GBGCell, voire totalement dans le .xib vu que y'en a un...

    Pour tes stones (rond noirs/blancs), c'est pas plus simple de le remplir également dans le .xib de la cell ?"


     


    Pourquoi il serait mieux de le faire dans le .xib?


     


     


  • AliGatorAliGator Membre, Modérateur
    novembre 2013 modifié #14

    Pourquoi il serait mieux de le faire dans le .xib?

    Bah à  cause du recycling.

    Si tu le fais dans le XIB (ou dans le awakeFromNib, ou dans le init de la cell) ces images ne vont être chargées qu'une fois, quand la cell va être créée/allouée. Alors que là  si tu le fais dans le cellForRowAtIndexPath tu charges les images(*) avec [UIImage imageNamed:...] à  chaque fois, même quand la cellule est juste recyclée à  partir d'une ancienne cellule déjà  existante en mémoire.

    (*) bon en pratique "+imageNamed:" utilise un cache interne donc l'impact n'est pas si grand, une fois l'image chargée et décodée depuis le disque elle est mise en cache et les demandes suivantes sont plus rapides.
    Mais quand même sur le principe cellForRowAtIndexPath n'est sensé se contenter de mettre à  jour que le strict minimum, donc d'adapter juste le contenu dynamique qui change d'une cellule à  l'autre, alors que tout ce qui est commun à  toutes tes cellules (comme les images de ronds blancs/noirs) c'est inutile de le refaire à  chaque fois, autant ne le faire qu'une seule fois à  la création/allocation de la cellule.
  • Merci AliGator! ::)


  • J'aime beaucoup les switch dans les cellAtIndexPath, mais là , j'pense que tu devrais plutôt retourner sur des ifs (avec le recule, quand je vois la duplication de code, j'suis désolé si ça semble aller à  reculons ce que je dis, mais ce n'est pas obligatoire):


    if (row < 5){} 


    else if(row==5){}


    else{}


     


    J'ai vu ces deux lignes dans tous les cases :


                cell.numStoneWhiteLabel.text = gbgDataCell.numStoneWhite;


                cell.numStoneBlackLabel.text = gbgDataCell.numStoneBlack;


    Tu peux les sortir du switch.


    À la limite, je sortirais aussi le  cell.userInteractionEnabled = NO; (en le sortant avant les tests, pour qu'il repasse à  YES dans le cas 6).


     


    Parce que y'a beaucoup de duplication de code.


    D'ailleurs, en parlant de switch, ça me fait étrange d'en voir un sans default case.

  • p.salvadorp.salvador Membre
    novembre 2013 modifié #17

    Ok Larme!


     


    Je suis apprenti, donc je vais faire comme tu dis et de plus, cela me fait de l'exercice. o:)


     


    Je crois que je n'ai pas très bien compris le fonctionnement du "cellForRowAtIndexPath". Sinon, je ne ferais pas toutes ces erreurs...

    Le "cellForRowAtIndexPath" est appelé pour chaque row? Si c'est le cas, cela devient beaucoup plus clair.

    Merci!


  • cellForRowAtIndexPath fait partie du DataSource.


    Mets un p'tit breakpoint, ou un NSLog de l'IndexPath, tu verras ;)


    Par contre, normalement, ce n'est appelé qu'au besoin de l'affichage (en bref, si t'as une liste de 3000 éléments, pas besoin de tous les charger, mais uniquement charger ceux visibles, ou qui ont déjà  été visibles, d'où le reuse).


  • OK!


     


    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    {

        return 7;

    }


     


    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{


    //...


    NSLog(@%i, [indexPath row]);


    //...


    }


     


    Console:


     


    2013-11-14 12:51:05.157 Test[1161:a0b] 0

    2013-11-14 12:51:05.163 Test[1161:a0b] 1

    2013-11-14 12:51:05.167 Test[1161:a0b] 2

    2013-11-14 12:51:05.170 Test[1161:a0b] 3

    2013-11-14 12:51:05.173 Test[1161:a0b] 4

    2013-11-14 12:51:05.176 Test[1161:a0b] 5

    2013-11-14 12:51:05.178 Test[1161:a0b] 6


     


    Claire!! 8--)


  • Voilà  modife faite!!


  • AliGatorAliGator Membre, Modérateur
    Si tu veux que ce soit plus clair, faut pas juste loguer l'indexPath à  chaque fois que cellForRow est appelé (= ça tu as vu que c'est à  chaque cellule) mais :
    - Aussi loguer quand une cellule est alloc/init (surcharger le initWithCoder ou awakeFromNib par exemple si tu as une cell faite par XIB/Storyboard) pour voir quand les cellules sont allouées / vraiment créées from scratch
    - Aussi loguer quand une cellule est recyclée en surchargant prepareForReuse ou des méthodes comme ça

    Et quand tu testes :
    - regarde tes logs au premier affichage certes (tu vas voir que certes cellForRow est appellé pour toutes les cellules visibles, mais aussi que toutes ces cellules sont alloc/init au départ puisqu'il n'y en a encore aucune à  recycler)
    - mais regarde-les aussi et surtout quand tu scrolles ta TableView (tu vas voir que cellForRow est appelé pour les nouvelles cellules à  afficher, et aussi que cela ne génère plus un alloc/init mais préfère recycler des cellules qui viennent de disparaitre de l'écran et ne servait plus)
  • Merci AliGator! :)


Connectez-vous ou Inscrivez-vous pour répondre.