Tri d'objets d'une classe modèle contenus dans un NSArray

Eddy58Eddy58 Membre
20:36 modifié dans API AppKit #1
Mes projets m'amènent à  présent à  utiliser le tri, que je n'ai pas encore eu l'occasion d'expérimenter, et je n'ai pas trouvé de doc très explicite sur le sujet.
Je voudrais trier un NSArray, tout d'abord à  chaque ajout d'un objet de ma classe modèle dans celui-ci, et ensuite répercuter les résultats dans  la TableView qui affiche les données du NSArray. Dans la TableView, je voudrais aussi dédier deux colonnes pour le tri inversé soit par date dans l'une, et par ordre alphabétique dans l'autre. Chaque objet de ma classe modèle contient diverses variables d'instances NSCalendarDate et NSString.

Je me pose les questions suivantes : ???
1) Quelle méthode utiliser pour faire comprendre que je veux faire un tri par rapport à  une certaine variable d'instance NSCalendarDate ou NSString de ma classe modèle ?
2) Comment se répercute le tri sur la tableview, selon le choix d'inversion choisi dans les columns headers ?

Autre précision, je n'utilise pas les bindings et ne veux pas les utiliser pour le moment... :o

Réponses

  • avril 2005 modifié #2
    Comme on peut utiliser le KVC sans utiliser les bindings, je te propose ceci: si tes objets répondent à  -valueForKey, tu peux utiliser les NSSortDescriptor (Ajouté dans Panther), ce qui donne par exemple:

    [tt]NSSortDecriptor* sortDesc1 = [[NSSortDescriptor alloc] initWithKey:@title ascending:YES];
    NSSortDecriptor* sortDesc2 = NSSortDescriptor alloc] initWithKey:@&quot;date&quot; ascending:NO];<br /><br />[myMutableArray  sortUsingDescriptors:[NSArray arrayWithObjects:sortDesc1,sortDesc2,nil;
    [sortDesc1 release];
    [sortDesc2 release];[/tt]
  • Eddy58Eddy58 Membre
    20:36 modifié #3
    Merci pour cette piste Renaud, je vais essayer ça, il va falloir que je configure ma classe modèle pour le KVC. :)
  • Eddy58Eddy58 Membre
    20:36 modifié #4
    J'ai implémenté le tri par dates, ça marche impeccable. Il ne me reste plus qu'à  mettre le tri par ordre alphabétique des colonnes voulues.
    C'est bien moins compliqué que je le pensais ! :P
    Rien à  faire dans le NSArray ou la classe modèle, c'est KVC "compliant" d'entrée et la méthode de tri trouve les accesseurs de la classe modèle comme une grande. :o
    Par contre, pour tenter "d'économiser" du code, j'ai essayé dans IB, après avoir mis en inactif mon code qui gère les actions dans le column header, les réglages de tri dans les colonnes, en mettant la même key que dans le code, mais ça faisait rien, la petite flèche apparaissait bien, mais aucun tri. Ca doit fonctionner d'une certaine façon ?
  • fouffouf Membre
    20:36 modifié #5
    Mais comment fait-on pour trier les NSArray sans KVC ? Il doit bien y avoir une solution.
  • 20:36 modifié #6
    Il y a deux méthodes:
    -sortUsingSelector: qui envoie un message à  un objet du tableau en utilisant le sélecteur placé en argurment comme sélecteur, et un autre élément du tableau comme argument.
    -sortUsingFunction: qui appelle une fonction qui prend 2 objets à  comparer comme arguments, ainsi qu'un paramètre extérieur.

    Mais perso, je trouve ça assez lourd, en particulier lorsque qu'on a plusieurs critères de tri, et ça oblige à  mettre du code spécifique pour chaque tri, ou presque.
  • Eddy58Eddy58 Membre
    20:36 modifié #7
    Oui, voici d'ailleurs un sujet qui traite de SortUsingSelector : :)
    http://www.cocoadev.com/index.pl?SortUsingSelector
  • muqaddarmuqaddar Administrateur
    20:36 modifié #8
    dans 1114867386:

    Comme on peut utiliser le KVC sans utiliser les bindings, je te propose ceci: si tes objets répondent à  -valueForKey, tu peux utiliser les NSSortDescriptor (Ajouté dans Panther), ce qui donne par exemple:

    [tt]NSSortDecriptor* sortDesc1 = [[NSSortDescriptor alloc] initWithKey:@title ascending:YES];
    NSSortDecriptor* sortDesc2 = NSSortDescriptor alloc] initWithKey:@&quot;date&quot; ascending:NO];<br /><br />[myMutableArray  sortUsingDescriptors:[NSArray arrayWithObjects:sortDesc1,sortDesc2,nil;
    [sortDesc1 release];
    [sortDesc2 release];[/tt]


    Déterrage de thread !
    Dites moi les gars, la ligne :
    [myMutableArray  sortUsingDescriptors:[NSArray arrayWithObjects:sortDesc1,sortDesc2,nil]];
    je ne vois pas trop ou la mettre dans ma classe modèle... ???
  • Eddy58Eddy58 Membre
    20:36 modifié #9
    J'ai mis la gestion du tri dans mon controleur. :)
  • VeillardVeillard Membre
    20:36 modifié #10
    Donc, en fin de compte, mon truc lourdingue, je peux le simplifier non ?

    NSSortDescriptor *aDescriptor;<br />	NSString *ident;<br />	BOOL tri;<br /><br /><br />	ident = [tableColumn identifier];<br />	if (_idColonne == ident)<br />	{<br />		tri = ! [[_ascendingDirection objectForKey: ident] boolValue];<br />		[_ascendingDirection setObject: [NSNumber numberWithBool: tri] forKey: ident];<br />	}<br />	else<br />	{<br />		tri = [[_ascendingDirection objectForKey: ident] boolValue];<br />		_idColonne = ident;<br />	}<br /><br />	aDescriptor=[[NSSortDescriptor alloc] initWithKey:[[tableColumn sortDescriptorPrototype] key] ascending: tri selector:@selector(compare:)];<br /><br />	[[tableView tableColumnWithIdentifier:[tableColumn identifier]] setSortDescriptorPrototype:aDescriptor];<br /><br />	NSArray *sortDescriptorArray = [NSArray arrayWithObject:aDescriptor];<br />	[aDescriptor release];<br /><br />	[tableView setSortDescriptors:sortDescriptorArray];<br /><br />	[_carnet sortUsingDescriptors:[tableView sortDescriptors]];<br /><br />	[tableView reloadData];<br />
    
  • muqaddarmuqaddar Administrateur
    20:36 modifié #11
    Mon mon code n'est pas KVC... enfin, c'est ce qu'il em dit...
  • VeillardVeillard Membre
    20:36 modifié #12
    J'utilise pourtant ceci, c'est bien du KVC non ?

    [plongeeNoField setObjectValue:[[_carnet objectAtIndex:_currentIndex] valueForKey:@&quot;noPlongee&quot;]];<br />
    
  • Eddy58Eddy58 Membre
    20:36 modifié #13
    Voici ma routine de tri, appelée en plusieurs occasions (initialisation, mouseDownInHeaderOfTableColumn, etc...). Ma classe modèle est on ne peut plus banale, et les keys font références à  mes accesseurs. :)

    [tt]
    // Tri dans la colonne choisie
    -(void)makeTri
    {
    if (datesDebutsChoix==YES) // Si choix DatesDebuts alors créer l'instance descripteur de tri correspondante
    {
    sortDescriptor=[[NSSortDescriptor alloc] initWithKey:@dateDebut ascending:datesDebutsAscending];
    }
    else if (societesChoix==YES) // Sinon si choix Societes alors créer l'instance descripteur de tri correspondante
    {
    sortDescriptor=[[NSSortDescriptor alloc] initWithKey:@identificationSociete ascending:societesAscending selector:@selector(caseInsensitiveCompare:)];
    }
    else if
    (...........autre colonnes)   
        sortDescriptors=[NSArray arrayWithObject:sortDescriptor]; // Créer l'array de descripteurs de tri
    tempArray=[clientsPrelevementsArray sortedArrayUsingDescriptors:sortDescriptors]; // Trier l'array clientsPrelevements avec les descripteurs et créer un array résultant temporaire
    [sortDescriptor release]; // Libérer le descripteur de tri
    [clientsPrelevementsArray release]; // Libérer l'ancien clientsPrelevementsArray
    clientsPrelevementsArray=[tempArray mutableCopy]; // Faire pointer clientsPrelevementsArray sur le nouvel array
    [clientsPrelevementsTableView reloadData]; // Mise à  jour de l'affichage de la tableview clients
    }
    [/tt]
  • VeillardVeillard Membre
    20:36 modifié #14
    OK merci Eddy, je vais étudier ton code.  ;)
  • MulotMulot Membre
    20:36 modifié #15
    Je deterre ce topic !

    J'ai quelques petites questions concernant les tableView:

        - j'ai une TableView qui m'affiche des Opérations (divers String, Dates, et double). Pas de soucis, à  l'ajout de chaque opération dans un MutableArray qui sert de dataSource à  la-dite tableView, je retrie le tableau en fonction d'une méthode par défaut, à  savoir par date d'opération.

    C'est là  qu'une première question arrive, lorsque que j'ai vu la possibilité des @selector et de performSelector, je me suis dit que lorsque ma tableView serait triée par un des attributs d'opération, le fait d'ajouter une nouvelle opération et de trier le tableau se ferait donc selon l'odre dans lequel la tableView était déjà  triée via la méthode courante selectionnée mise dans ma variable SEL. Est-ce une bonne idée une meilleure façon existe-t-elle ?

        - autre point, pour l'instant, sous IB, impossible de trier une colonne de String, j'ai pourtant spécifié ma value Key operationName (avec un accesseur du même nom en plus), et choisis la méthode compare: , lorsque que je clique dans la tete de colonne, la flèche est bien soit asc ou desc, mais pas de réponse, faut-il recharger les données de la table ensuite ? Est-ce que il est nécessaire que ça soit la datasource de triée, et pas seulement "l'affichage apparant" dans la TableView ?

    Sinon avec ce que j'ai lu dans un post précédent, je vais essayer en utiliser la méthode de mouseDownOnInHeaderOfTableColumn.
Connectez-vous ou Inscrivez-vous pour répondre.