Déplacer une section d'une UITableView ?
Bonjour,
Cela fait un moment que je ne fais de dev iOS mais je dois maintenir une app et j'ai donc une modification à faire.
C'est une app de résultats sportifs, où je récupère des données par catégorie et numéro de course (entre autres) le tout géré par CoreData. Les 6 catégories étaient donc :
E1, E2, E3, EJ, EY, EW
Ces catégories sont donc les sections de mon UITableView. Le gros avantage était que le tri par catégorie me donnait le bon ordre pour mes sections.
Mais cette année il y a une nouvelle catégorie appelée "GP". Cette catégorie se retrouve en dernier une fois le tri effectuée par NSFetchedResultsController : E1, E2, ..... , EW, GP.
Mais cette catégorie GP doit se trouver en premier : GP, E1, E2, ....
Y-a-t il un moyen simple de faire en sorte que la section se retrouve en premier dans mon UITableView ?
J'ai cherché pour faire ça juste après le performFetch mais je n'ai pas trouvé . Faut dire que ça doit faire 2 ou 3 ans que je ne fais plus de dev alors j'ai un peu de mal :-(
Merci d'avance pour le coup de main !
Sergio
Réponses
Une solution normale serait d'ajouter une entité dans la base CoreData pour associer chaque catégorie à un ordre de classement. Du coup il y aurait juste une ligne de code à modifier pour que la clé de tri ne soit plus le nom de la catégorie mais l'ordre de classement.
Malheureusement la modification du schéma CoreData n'est pas simple si on veut que la nouvelle version de l'application lise les anciennes bases CoreData et crée cette entité supplémentaire à la volée ; il faut jouer avec les versions de schéma.
Une autre solution serait de bricoler le NSSortDescriptor utilisé lors de la création du NSFetchedResultsController. Il faudrait créer un NSSortDescriptor avec un bloc NSComparator dans lequel tu forces GP à être au début de la liste. C'est un affreux bricolo mais pas très compliqué à coder.
Merci pour les idées.
Une entité dans la base CoreData : une bonne idée mais ça risque de me faire quelques modifs et donc du test à faire, et donc du temps (c'est un championnat du monde, 1ère manche dans 10 jours).
Ceci dit, je retiens !
Le NSSortDescriptor : j'y ai pensé mais à priori ce n'est pas possible car ce NSSortDescriptor est plus ou moins compilé et transmis au SQLite et on ne peut pas appeler sa propre méthode pour le selector. C'est ce que j'ai lu dans mes recherches sur le Net.
Sinon entre temps, j'ai trouvé peut-être une autre solution : faire 2 NSFetchedResultsController alimentant ma UITableView, un avec la nouvelle categorie GP , le second avec les autres catégories.
S'il y a d'autres idées, je suis preneur
Oui. J'avais jeté mon dévolu sur -initWithKey:ascending:comparator: ou +sortDescriptorWithKey:ascending:comparator: qui me paraissent simples à mettre en oeuvre dans ce cas précis.
Deux NSFetchedResultsController ça me paraà®t plus compliqué à mettre en oeuvre. L'interface de NSFetchedResultsController est vraiment pensée pour qu'une instance soit appairée avec un UITableViewController.
Solution facile et moche : Tu appelles ta nouvelle catégorie "AAGP" et au moment de l'affichage, tu enlèves les "AA".
Comment enlever les "AA" ?
Si tu ne passes pas par un datasource en code (ce que j'imagine ; sinon tu peux le faire), mais par des "bindings" : tu peux créer une @property realTitleCategory sur tes entités et c'est celle-là que tu affiches.
Mon idée est basée sur des hypothèses sur comment marche le FetchMachin (que je n'ai jamais utilisé).
Si c'est pas clair, n'hésite pas à me demander des compléments.
Pour ce qui est du NSSortDescriptor dans un NSFetchedResultsController ce n'est à priori pas possible.J'ai pas mal cherché autour de ces 2 classes sur stackOverflow et les intervenants parlent souvent de problèmes avec son propre NSSortDescriptor , on récupère en général une erreur "unsupported NSSortDescriptor". J'ai essayé avec un block et c'est ce que j'ai eu. Il y a peut-être un moyen mais je pense que ce n'est pas simple.
En fait j'ai repris l'idée de jpimbert , j'ai rajouté une entité categOrder et lorsque j'importe les données j'ai juste à mettre une valeur par défaut pour ce categOrder (1 par exemple) et 0 pour la categorie GP. Autre avantage : je pourrais éventuellement modifier l'ordre d'affichage des catégories. Ca a été finalement peu de boulot et ça fonctionne :-)
En tous cas , merci pour les propositions
Sergio
Ce n'est pas une application déjà en production, avec des fichiers SQLite déjà existants avec l'ancien format ?
J'avais cru comprendre ça car tu disais que c'est une application en maintenance.
Si c'est une application toute neuve, l'entité supplémentaire est le plus simple à coder.
Dans le cas contraire il aurait fallu gérer le versionning de schéma pour convertir les fichiers déjà existants.
La doc de NSFetchRequest.sortDescriptors ne mentionne même pas cette limitation.
Je n'ai pas étudié le truc à fond, mais est-ce parce que ça transforme les requêtes en SQL-lookalike, et que du coup le sort avec un block est intraduisible ? Ce qui serait également " expliqué " par la limitation sur les NSPredicate qui ne peuvent être avec block non plus dû lors de recherches CoreData.
La conversion est transparente s'il s'agit d'un simple ajout de propriété.
Mais il y a peut-être quelques lignes à ajouter lors de la création de la stack coredata pour avoir l'option de migration automatique.
Pour compléter:
Il est possible d'utiliser un NSSortDescriptor qui ne se traduit pas en SQL à condition que tous les objets concernés soient déjà chargés en mémoire.
Il faut donc déjà faire une première requête pour charger les objets en mémoire (sans "fault") puis utiliser le tri avancé.
C'est une technique qui n'est pas documentée, donc à déconseiller... mais ça peut dépanner.
L'autre possibilité c'est de transférer les objets dans un store temporaire qui ne soit pas en SQLLite.
À propos de migration, si certains doivent gérer des migrations plus complexes, voici un lien bien utile.
https://www.objc.io/issues/4-core-data/core-data-migration/
Je me suis basé dessus pour mettre en place les transitions un peu délicates entre versions.
EDIT:
le projet github https://github.com/objcio/issue-4-core-data-migration