Selector ou pas ?

OkidokiOkidoki Membre
12:44 modifié dans API AppKit #1
Bonjour,

J'aimerais savoir comment appeler dynamiquement la methode d'une classe (disons la classe "employe") dans la methode d'une autre classe (la classe "entreprise").

L'idée est la suivant: la classe "entreprise" ayant comme attribut un tableau  d'objets de type "employe" (NSMutableArray), et chacun des employés répondant à  des méthodes (telles que "salaire" ou "cotisations"), je cherche à  écrire une méthode générique de la classe "entreprise" qui me permettrait d'avoir la somme (sur tous les employés) des salaires et des cotisations sans devoir écrire une fonction pour chacun des attributs. Autrement dit, j'aimerais avoir une méthode dans la classe "entreprise" dans laquelle je puisse passer la méthode d'une autre classe en argument. J'ai tenté çà  (quelques lignes de code valent mieux que mille mots...):


Dans "employe":

- (int) salaire
{
return salaire;
}

Dans "entreprise":

- (int) sumStat:(SEL)stat
{
int nbEmployes = [employes count];
int i;
int total = 0;

for (i = 0; i < nbEmployes; i++)
{
total = total + (int)[[employes objectAtIndex:i] stat];
}
return total;
}

- (int) sumSalaires
{
SEL action = @selector (salaire);
return [self sumStat: action];
}

Et dans "employe":

- (int) salaire
{
return salaire;
}

Ca ne fonctionne pas. Quelqu'un aurait-il une idée ?

Merci d'avance !

Réponses

  • ChachaChacha Membre
    12:44 modifié #2
    L'utilisation d'un selector n'est pas si simple que vous l'avez écrit.
    Voyez la famille "performSelector" pour les cas simple, et tournez-vous du côté de NSInvocation pour des cas comme le votre où vous vous intéressez à  la valeur de retour.
    Ma réponse est un peu évasive, mais si vous avez un problème, n'hésitez pas à  reposter.

    +
    Chacha
  • 12:44 modifié #3
    Une ligne de code vaut mieux qu'un long discours (Panther minimum):
    [tt]NSLog(@%@",[monEntreprise valueForKeyPath:@employes.@sum.salaire"]);[/tt]
  • Eddy58Eddy58 Membre
    novembre 2005 modifié #4
    @Chacha : Tiens...on se vouvoie sur OC maintenant ? ;)

    Le code de Renaud doit normalement résoudre le problème, mais ton code Okidoki me parait curieux pour un traitement aussi classique, je pense que tu n'es pas trop familiarisé avec la notion de méthode accesseur et tu as essayé de te débrouiller avec @selector().
    Il te faut faire un outlet de la classe Entreprise vers la classe Employé, puis mettre la directive #import "Employe.h" dans ton fichier "Entreprise.h". Et là  tu peux accéder à  toutes les méthodes ta classe "Employé". Le code devrait ressembler à  ça (j'ai volontairement omis le NSEnumerator à  la place de la boucle For) :
    [tt]
    -(int)sumStat
    {
       int nbEmployes = [employes count];
       int i;
       int total = 0;
       
       for (i = 0; i < nbEmployes; i++)
       {
          total = total + [[employes objectAtIndex:i] salaire];
       }
       return total;
    }

    -(int)sumSalaires
    {
       return [self sumStat];
    }
    [/tt]
    Je me demande aussi pourquoi 2 méthodes différentes alors qu'une seule suffirait. En fin de compte, c'est le problème classique de communication entre classes. Cela me rappel un topic, tu peux aller voir ici et télécharger le petit projet d'exemple. Si tu as des questions n'hésites pas...:)
    Bon, il est tard, j'espère que je n'ai rien oublié ??
    Ha si, bienvenue sur OC Okidoki, et là  je pense que pour fêter ton arrivée sur OC, tu ne pourrais pas faire mieux que d'offrir une tournée générale (ce qui serait un minimum) ! :p :p
  • OkidokiOkidoki Membre
    12:44 modifié #5
    Merci tout le monde pour les réponses ! Pourquoi faire simple quand on peut faire compliqué ? Parce qu'effectivement, la petite ligne de code de Renaud était ce qu'il me fallait. J'utilise en général exactement le même code que celui proposé par Eddy, mais en pensant aux pointeurs de fonctions utilisées en C, je voulais savoir comment faire le même genre de chose avec des méthodes en Objective-C, histoire de faire des fonctions plus génériques, une fonction qui serait capable de calculer la somme sur un tableau de n'importe quel attribut d'"employe".

    J'utilise donc cette simple ligne:

    sommeSalaires =  [[employes valueForKeyPath:@"@sum.salaire"] intValue];

    Je venais aussi de découvrir la classe NSEnumerator dont parle Eddy. ça ne change pas grand chose à  la concision du code, mais c'est toujours bon à  savoir.

    Pour la tournée générale, habillez-vous chaudement, c'est au Québec que ça se passe !  ;)
  • AliGatorAliGator Membre, Modérateur
    12:44 modifié #6
    dans 1132275981:

    Une ligne de code vaut mieux qu'un long discours (Panther minimum):
    [tt]NSLog(@%@",[monEntreprise valueForKeyPath:@employes.@sum.salaire"]);[/tt]
    Tu pourrais expliquer un poil, Renaud ?

    Je maà®trise pas encore trop trop les KeyPath, sur le principe j'ai compris, genre si ta classe entreprise a une variable d'instance patron (de la même classe que employés, pour faire simple), je comprend que [monEnterprise valueForKeyPath:@patron.salaire] qui en somme est équivalent (mais plus court) à  [[monEntreprise valueForKey:@patron] valueForKey:@salaire]; et que grace au KVC ça accède directement aux variables d'instances (par l'accesseur dédié s'il existe et a un nom standard, ou par accès direct sinon).

    Bref tout ça j'ai bien compris... mais c'est ton "@sum"; du coup qui me trouble. Le "@" devant j'imagine que c'est pour préciser qu'il s'agit d'un @selector mais ce selector, tu dois le définir ou il est prédéfini dans Cocoa pour faire la somme des valeurs de la clé suivante dans le KVP, ou un truc du genre ?

    Déjà  à  quoi est équivalent ton KVP ?
    [[monEnterprise valueForKey:@employees] performSelector:@selector(sum) withObject:@salaire]; ? Un truc du genre ?
  • novembre 2005 modifié #7
    Les @machin sont des opérateurs de collection. Il y en a quelques uns qui ont été définis, comme @avg (average), @max, @count, @min,@unionOfSet,... Il ne s'agit donc pas d'un selector, et il n'est pour l'instant pas possible d'en définir (dixit la doc). Sinon pour le reste, tu as pigé.

    Sinon, en code normal, ce serait plutot équivalent à  un hypothéthique:
    [tt][[monEnterprise valueForKey:@employees] sumOfValuesForKey:@salaire];[/tt]

    @okidoki
    Si tu peux utiliser une valeur SEL sur un objet, il faut utiliser la méthode performSelector:.
    [tt]- (int) sumStat:(SEL)stat
    {
       int nbEmployes = [employes count];
       int i;
       int total = 0;
       
       for (i = 0; i < nbEmployes; i++)
       {
          total += (int)[[employes objectAtIndex:i] performSelector:stat];
          // a = a + b; peut s'écrire a+=b;
       }
       return total;
    }[/tt]
  • ChachaChacha Membre
    12:44 modifié #8
    Je n'ai pas encore bien compris les keypath...
    Par exemple, l'autre jour j'avais un tableau de NSNumber, et je voulais calculer la somme de son contenu.
    C'est quoi la solution?
    [mon tab valueForKey:@"@sum.floatvalue"] ?
    [mon tab valueForKey:@floatvalue.@sum";] ?

    Là  tout de suite je ne peux pas vérifier, mon powerbook est parti chez le docteur :-(

    +
    Chacha
  • janvier 2006 modifié #9
    Aucun des 2 en fait.

    [monTab valueForKeyPath:@"@sum.self"];

    Alors:
    1. mon tab en un mot
    2. valueForKeyPath et pas valueForKey (les opérateurs ne fonctionnent qu'avec les keypath).
    enfin le sérieux: 3. l'opérateur @sum ne fonctionne qu'avec des objets, en passant par floatValue, tu reviens à  un type "primitif" qu'il ne sait pas gérer. Je dirais aussi que le passage par floatValue n'est pas nécessaire car c'est à  NSNumber d'effecteur les conversions des différents types de nombres, donc tu mets "self" pour dire d'additionner les nombres directement entre eux.

    voili voulou.
  • ChachaChacha Membre
    janvier 2006 modifié #10
    dans 1136910693:

    1. mon tab en un mot  >:)


    2. valueForKeyPath et pas valueForKey (les opérateurs ne fonctionnent qu'avec les keypath).  :o



    [monTab valueForKeyPath:@"@sum.self"];  <3 <br />


    +
    Chacha

    PS : En tous cas, merci ! et ne t'inquiète pas pour les smileys, ça doit être la fatigue  ;)
  • 12:44 modifié #11
    Le pire c'est que j'en ai mis moi aussi, mais je les ai viré avant de poster ;) (ouuuuups)
  • AliGatorAliGator Membre, Modérateur
    12:44 modifié #12
    [PJ]
    tssss c'est pô bien ça, faire des fôtes aussi basiques ;)
    Ralala... faut arrêter les  :p :p , hein Renaud ?  ;D
    [/PJ]
Connectez-vous ou Inscrivez-vous pour répondre.