Comparer son style de programmation

Philippe49Philippe49 Membre
septembre 2007 modifié dans API AppKit #1
C'est mort actuellement sur le site !

Voilà  une petite source de discussion pour animer <3 <3 o:) <br />
On connaà®t la méthode de NSString  
- (NSArray *)componentsSeparatedByString:(NSString *)separator
qui décompose une chaà®ne en un tableau de sous-chaà®ne.

Quel est selon vous un bon code pour une catégorie
@interface NSString (componentsSeparatedByCharactersFromString)
-(NSArray *) componentsSeparatedByCharactersFromString:(NSString *) characters;
@end


ou

@interface NSString (componentsSeparatedByCharacters)
-(NSArray *) componentsSeparatedByCharacters:(NSCharacterSet *) characterSet;
@end


=====================================================

Return Value
An NSArray object containing substrings from the receiver that have been divided by separators.

Discussion

The substrings in the array appear in the order they did in the receiver. If the string begins or ends with the separator, the method ignores. For example, this code fragment:

NSString * string = @(Norman, Stanley, Fletcher);
NSArray *listItems = [string componentsSeparatedByCharactersFromString:@(, )];
produces an array { @Norman, @Stanley, @Fletcher }.

If string begins with a comma and space"for example, ", Norman, Stanley, Fletcher""the array has these contents: { @Norman, @Stanley, @Fletcher }

If string has no separators"for example, "Norman""the array contains the string itself, in this case { @Norman }.
«1

Réponses

  • schlumschlum Membre
    20:30 modifié #2
    Bon, j'ai lu deux fois, mais rien compris...  :o
  • psychoh13psychoh13 Mothership Developer Membre
    20:30 modifié #3
    Personnellement, je pense que la deuxième solution serait plus appropriée. Il vaut mieux être cohérent. Si dans la méthode déjà  présente on utilise une NSString c'est parce que les caractères de la chaà®ne mais aussi leur ordre doit être respecté.

    Tandis que si tu utilises un NSCharacterSet c'est pour dire que "l'un des caractères de la série sert de séparateur", il n'y a là  aucune notion d'ordre, seulement de présence, d'ailleurs, dans une NSString un caractère peut s'y trouver plusieurs fois tandis que dans NSCharacterSet chaque caractère ne s'y trouve qu'une seule fois.
  • BruBru Membre
    20:30 modifié #4
    dans 1190114537:

    Personnellement, je pense que la deuxième solution serait plus appropriée. Il vaut mieux être cohérent. Si dans la méthode déjà  présente on utilise une NSString c'est parce que les caractères de la chaà®ne mais aussi leur ordre doit être respecté.

    Tandis que si tu utilises un NSCharacterSet c'est pour dire que "l'un des caractères de la série sert de séparateur", il n'y a là  aucune notion d'ordre, seulement de présence, d'ailleurs, dans une NSString un caractère peut s'y trouver plusieurs fois tandis que dans NSCharacterSet chaque caractère ne s'y trouve qu'une seule fois.


    Ouaip, sauf que...

    J'ai un fichier texte Windows.
    Je veux récupérer un tableau des lignes composant ce texte.
    Le séparateur c'est CRLF (soit 2 caractères).
    Je fais comment avec mon NSCharecterSet ?

    .
  • schlumschlum Membre
    20:30 modifié #5
    D'ailleurs pas seulement pour Windows... Pour beaucoup de protocoles réseau aussi.
  • Philippe49Philippe49 Membre
    20:30 modifié #6
    dans 1190109535:

    Bon, j'ai lu deux fois, mais rien compris...  :o


    Comment feriez-vous le code de la méthode ?

    je me lance pour recevoir les coups :  :)


    @implementation NSString (componentsSeparatedByCharactersFromString)
    -(NSArray *) componentsSeparatedByCharactersFromString:(NSString *) characters
    {
    NSScanner * scanner=[NSScanner scannerWithString:self];
    NSCharacterSet * charactersToBeSkipped=[NSCharacterSet characterSetWithCharactersInString:characters];
    NSMutableArray * array=[NSMutableArray array];
    NSString * current;
    while( [scanner scanCharactersFromSet:charactersToBeSkipped intoString:&current],
                      [scanner scanUpToCharactersFromSet:charactersToBeSkipped intoString:&current])
          {
    [array addObject:current];
    }
    return [[array retain] autorelease];
    }
    @end


    Est-ce votre conception ... avez-vous une autre approche ?
  • schlumschlum Membre
    20:30 modifié #7
    Moi je le ferais en C... Je fais toujours mes parsings en C  :P
  • psychoh13psychoh13 Mothership Developer Membre
    20:30 modifié #8
    dans 1190116683:
    Ouaip, sauf que...

    J'ai un fichier texte Windows.
    Je veux récupérer un tableau des lignes composant ce texte.
    Le séparateur c'est CRLF (soit 2 caractères).
    Je fais comment avec mon NSCharecterSet ?

    .


    Bah là  tu utilises la méthode fournie !
  • BruBru Membre
    20:30 modifié #9
    dans 1190117171:

    Bah là  tu utilises la méthode fournie !


    Plutôt que de réinventer 36 roues pour emprunter le même chemin, pourquoi pas sous-classer NSSet pour implanter un NSStringSet ?

    .
  • psychoh13psychoh13 Mothership Developer Membre
    20:30 modifié #10
    dans 1190117028:


    Comment feriez-vous le code de la méthode ?

    je me lance pour recevoir les coups :  :)


    @implementation NSString (componentsSeparatedByCharactersFromString)
    -(NSArray *) componentsSeparatedByCharactersFromString:(NSString *) characters
    {
    NSScanner * scanner=[NSScanner scannerWithString:self];
    NSCharacterSet * charactersToBeSkipped=[NSCharacterSet characterSetWithCharactersInString:characters];
    NSMutableArray * array=[NSMutableArray array];
    NSString * current;
    while( [scanner scanCharactersFromSet:charactersToBeSkipped intoString:&current],
                      [scanner scanUpToCharactersFromSet:charactersToBeSkipped intoString:&current])
           {
    [array addObject:current];
    }
    return [[array retain] autorelease];
    }
    @end


    Est-ce votre conception ... avez-vous une autre approche ?



    Déjà  tu peux pas mettre de virgule dans la condition d'un while ! (et dans aucune condition d'ailleurs) et tu as plus simple je pense, en utilisant uniquement les méthodes de NSString :
    - (NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet options:(unsigned int)mask range:(NSRange)aRange
    - (NSString *)substringWithRange:(NSRange)aRange
  • psychoh13psychoh13 Mothership Developer Membre
    20:30 modifié #11
    dans 1190117684:

    dans 1190117171:

    Bah là  tu utilises la méthode fournie !


    Plutôt que de réinventer 36 roues pour emprunter le même chemin, pourquoi pas sous-classer NSSet pour implanter un NSStringSet ?

    .


    Quel intérêt ?  B)
  • Philippe49Philippe49 Membre
    20:30 modifié #12
    dans 1190117171:


    Bah là  tu utilises la méthode fournie !


    doc de NSCharacterSet :

    An NSCharacterSet object represents a set of Unicode-compliant characters.
  • BruBru Membre
    20:30 modifié #13
    dans 11901177:

    Quel intérêt ?  B)


    Ben celui de remplir ce topic, comme demandé par Philippe49 !

    .
  • Philippe49Philippe49 Membre
    20:30 modifié #14
    dans 1190117755:


    Déjà  tu peux pas mettre de virgule dans la condition d'un while ! (et dans aucune condition d'ailleurs)


    si, c'est sans problème
    En C, et donc en objective-C, le résultat d'une expression (A,B,C) vaut le résultat de la dernière expression (la plus à  droite) sauf lorsqu'il s'agit d'un eliste d'arguments d'une méthode
  • Philippe49Philippe49 Membre
    20:30 modifié #15
    dans 1190117946:

    dans 11901177:

    Quel intérêt ?  B)


    Ben celui de remplir ce topic, comme demandé par Philippe49 !

    .


    ;D ;D ;D
  • psychoh13psychoh13 Mothership Developer Membre
    20:30 modifié #16
    dans 1190118094:
    si, c'est sans problème
    En C, et donc en objective-C, le résultat d'une expression (A,B,C) vaut le résultat de la dernière expression (la plus à  droite) sauf lorsqu'il s'agit d'un eliste d'arguments d'une méthode


    C'est moche ! ???
  • Philippe49Philippe49 Membre
    20:30 modifié #17
    dans 1190118214:


    C'est moche ! ???


    Peut-être pas au niveau de la pensée, au niveau de l'algorithme,
    peut-être au niveau de la lecture si on n'en a pas l'habitude.
  • Philippe49Philippe49 Membre
    20:30 modifié #18
    dans 1190117157:

    Moi je le ferais en C... Je fais toujours mes parsings en C  :P


    oui, surtout qu'au niveau rapidité je doute des méthodes objective-C
  • BruBru Membre
    20:30 modifié #19
    dans 1190117028:

    Comment feriez-vous le code de la méthode ?
    je me lance pour recevoir les coups :  :)
    [...]
    Est-ce votre conception ... avez-vous une autre approche ?


    Sans polémiquer sur la manière de coder (qui est propre à  chacun, et aussi pour éviter les "c'est moche"), je me permets juste de te faire remarquer qu'une méthode non directement liée à  l'UI devrait faire attention à  l'utilisation de l'autorelease pool.
    Dans ton exemple, j'encadrerais ton code par une allocation NSautoreleasePool puis par sa destruction, ou alors, j'éviterais l'emploi des méthodes convénientes pour créer les objets.

    .
  • Philippe49Philippe49 Membre
    20:30 modifié #20
    dans 1190118512:

    Sans polémiquer sur la manière de coder

    mais le post est en partie pour cela ...

    dans 1190118512:

    Une méthode non directement liée à  l'UI devrait faire attention à  l'utilisation de l'autorelease pool.
    Dans ton exemple, j'encadrerais ton code par une allocation NSautoreleasePool puis par sa destruction, ou alors, j'éviterais l'emploi des méthodes convénientes pour créer les objets.


    Si je comprends bien, tu ferais plutôt un alloc-init pour l'objet array renvoyé, avec un
    return [array autorelease],

    Les autres objets de la fonction seraient dans un pool spécifique afin de disparaà®tre le plus vite possible ...
  • BruBru Membre
    20:30 modifié #21
    dans 1190118897:

    Si je comprends bien, tu ferais plutôt un alloc-init pour l'objet array renvoyé, avec un
    return [array autorelease],
    Les autres objets de la fonction seraient dans un pool spécifique afin que disparaà®tre le plus vite possible ...


    C'est tout à  fait cela.
    C'est d'autant plus important si tu appelles cette méthode dans une longue boucle par exemple.

    .
  • psychoh13psychoh13 Mothership Developer Membre
    septembre 2007 modifié #22
    Voilà , je me suis amusé à  faire cette méthodes qu'a indiqué Philippe49.

    J'en ai fait deux implémentations en Objective-C, la première, la plus simple, utilisant l'envoie de message normal, et la deuxième, optimisée, qui utilise les pointeurs de méthodes et les imps :

    Première implémentation :

    @interface NSString (NSStringPSYAdds)<br />-(NSArray *) componentsSeparatedByCharacters:(NSCharacterSet *) aSet;<br />@end<br /><br />@implementation NSString (NSStringPSYAdds)<br />-(NSArray *) componentsSeparatedByCharacters:(NSCharacterSet *) aSet<br />{<br />&nbsp; &nbsp; NSMutableArray *strings = [NSMutableArray array];<br />&nbsp; &nbsp; unsigned strLength = [self length];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSRange<br />&nbsp; &nbsp; &nbsp; &nbsp; verifyRange = NSMakeRange(0, strLength),<br />&nbsp; &nbsp; &nbsp; &nbsp; resultRange = NSMakeRange(0, 1),<br />&nbsp; &nbsp; &nbsp; &nbsp; subRange = NSMakeRange(0, -1);<br /><br />&nbsp; &nbsp; resultRange = [self rangeOfCharacterFromSet:aSet options:NSLiteralSearch<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; range:verifyRange];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; while(resultRange.location != NSNotFound &amp;&amp; resultRange.location != strLength)<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; subRange.location = verifyRange.location;<br />&nbsp; &nbsp; &nbsp; &nbsp; subRange.length = resultRange.location - verifyRange.location;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; [strings addObject:[self substringWithRange:subRange]];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; verifyRange.location = subRange.location + subRange.length + 1;<br />&nbsp; &nbsp; &nbsp; &nbsp; verifyRange.length = strLength - verifyRange.location;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; resultRange = [self rangeOfCharacterFromSet:aSet options:NSLiteralSearch<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; range:verifyRange];<br />&nbsp; &nbsp; }<br /><br />&nbsp; &nbsp; [strings addObject:[self substringWithRange:verifyRange]];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return strings;<br />}<br /><br />@end
    


    Deuxième implémentation :

    @implementation NSString (NSStringPSYAdds)<br />-(NSArray *) componentsSeparatedByCharacters:(NSCharacterSet *) aSet<br />{<br />&nbsp; &nbsp; NSMutableArray *strings = [NSMutableArray array];<br />&nbsp; &nbsp; unsigned strLength = [self length];<br /><br />&nbsp; &nbsp; // Paperasse nécessaire pour utiliser les implémentations<br />&nbsp; &nbsp; // On doit garder le sélecteur pour le passer en deuxième argument<br />&nbsp; &nbsp; SEL rangeOfCharSel = @selector(rangeOfCharacterFromSet:options:range:);<br /><br />&nbsp; &nbsp; // On définit un pointeur de fonction spécifique, c&#39;est ce qui est conseillé par Apple<br />&nbsp; &nbsp; NSRange (*rangeOfCharImp)(id, SEL, NSCharacterSet*, unsigned int, NSRange) =<br />&nbsp; &nbsp; // C&#39;est moche mais c&#39;est un simple cast pour éviter d&#39;avoir un warning<br />&nbsp; &nbsp; &nbsp; &nbsp; (NSRange (*)(id, SEL, NSCharacterSet*, unsigned int, NSRange))[self methodForSelector:rangeOfCharSel];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; SEL substringSel = @selector(substringWithRange:);<br />&nbsp; &nbsp; NSString *(*substringImp)(id, SEL, NSRange) =<br />&nbsp; &nbsp; &nbsp; &nbsp; (NSString *(*)(id, SEL, NSRange))[self methodForSelector:substringSel];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; SEL addObjectSel = @selector(addObject:);<br />&nbsp; &nbsp; void (*addObjectImp)(id, SEL, id) =<br />&nbsp; &nbsp; &nbsp; &nbsp; (void (*)(id, SEL, id))[strings methodForSelector:addObjectSel];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSRange<br />&nbsp; &nbsp; &nbsp; &nbsp; verifyRange = NSMakeRange(0, strLength),<br />&nbsp; &nbsp; &nbsp; &nbsp; resultRange = NSMakeRange(0, 1),<br />&nbsp; &nbsp; &nbsp; &nbsp; subRange = NSMakeRange(0, -1);<br /><br />&nbsp; &nbsp; resultRange = rangeOfCharImp(self, rangeOfCharSel, aSet, NSLiteralSearch, verifyRange);<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; while(resultRange.location != NSNotFound &amp;&amp; resultRange.location != strLength)<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; subRange.location = verifyRange.location;<br />&nbsp; &nbsp; &nbsp; &nbsp; subRange.length = resultRange.location - verifyRange.location;<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; addObjectImp(strings, addObjectSel, substringImp(self, substringSel, subRange));<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; verifyRange.location = subRange.location + subRange.length + 1;<br />&nbsp; &nbsp; &nbsp; &nbsp; verifyRange.length = strLength - verifyRange.location;<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; resultRange = rangeOfCharImp(self, rangeOfCharSel, aSet, NSLiteralSearch, verifyRange);<br />&nbsp; &nbsp; }<br /><br />&nbsp; &nbsp; addObjectImp(strings, addObjectSel, substringImp(self, substringSel, verifyRange));<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return strings;<br />}<br /><br />@end
    


    PS : Après quelques tests, j'ai pu noter ceci à  propos des pointeurs de méthodes :

    La création d'un pointeur de méthode spécifique (et donc le cast) n'est nécessaire que si le type retourné par la méthode n'est pas un objet. Je pense qu'il est possible d'étendre les possibilités aux pointeurs en général, le cast d'un pointeur (id) à  un pointeur d'un autre type (void *, int *, etc.) ne devrait pas poser de problème.
    Donc dans le cas d'une méthode retournant un id, un objet définis ou simplement void on peut simplement définir une variable de type IMP :
    IMP substringImp = [self methodForSelector:substringSel];
    

    Dans le cas d'un type void, étant donné qu'on se fiche de la valeur de retour (puisqu'il n'y en a pas) utiliser une fonction qui ne retourne pas le bon type ne pose pas de problème.
  • Philippe49Philippe49 Membre
    20:30 modifié #23
    dans 1190139612:

    la deuxième, optimisée, qui utilise les pointeurs de méthodes et les imps :


    Qu'est-ce qui te fait dire que l'utilisation des pointeurs de méthodes optimise ?

    Pour moi, mais je ne suis pas un spécialiste, après la compilation et l'optimisation associée, gcc a du faire sa cuisine pour optimiser au mieux selon ses propres critères, ... que l'on ne connaà®t pas vraiment.


  • psychoh13psychoh13 Mothership Developer Membre
    20:30 modifié #24
    Malgré tous les efforts de GCC il n'est pas capable d'optimiser ça au max.

    Il faut savoir ce qu'il se passe lorsque tu écris un message :

    Lorsque tu écris ça :
    [monObjet maMethodeEtSonArgument: 5];
    


    GCC va remplacer ce message par une fonction C :

    objc_msgSend(monObjet, @selector(maMethodeEtSonArgument:), 5);
    


    En gros c'est ça, bien sûr il convertit directement le @selector() en variable SEL. GCC fera un remplacement de ce type systématiquement. Il ne peut pas faire plus.
    Lorsque tu compiles ton application Objective-C, ton code est linké à  la bibliothèque libobjc qui contient la définition de objc_msgSend().

    Que fait objc_msgSend() ?
    Lorsque la fonction est exécutée, elle commence d'abord par vérifier si le message envoyé n'est pas déjà  dans un cache, si c'est le cas elle exécute la méthode en lui passant les arguments du message ainsi que l'objet à  qui on a envoyé ce message (le fameux self) et le sélecteur de la méthode (le fameux _cmd).

    Dans le cas où la méthode n'est pas cachée, donc qu'elle n'a jamais été exécutée, objc_msgSend() va chercher grâce au pointeur de Class "isa" (que tout objet Objective-C a) ainsi que le sélecteur de la méthode, l'implémentation de la méthode à  exécuter, elle cherche d'abord dans la classe elle-même, si elle ne trouve pas elle cherche dans les méthodes de la super-classe et ainsi de suite. Si elle trouve la méthode, elle la cache et l'exécute en lui passant les arguments, puis elle renvoie la valeur de retour du message comme si c'était elle qui la renvoyait.

    Si la méthode n'est pas trouvée, ni dans la cache ni grâce au pointeur de classe, objc_msgSend() cherche si l'objet est capable d'exécuté le message : -forward::, si c'est le cas, elle passe à  cette méthode la liste des arguments, le sélecteur et l'objet. C'est ce système qui permet de "donner une seconde chance d'exécuter un message".

    Si la méthode forward:: n'est pas trouvée, alors là  elle cherche la méthode error: et si elle-même ne s'y trouve pas, bah c'est objc_msgSend() qui lance l'erreur et quitte le programme.

    Donc tu peux voir que l'envoie de message est un mécanisme complexe. Les pointeurs de méthodes que j'utilise en l'occurrence permettent de contourner ce système. Il consiste à  faire cette recherche une et une seule fois par message, ensuite pour utiliser l'implémentation je fais comme objc_msgSend(), je passe à  ma méthode l'objet sur qui la méthode est exécuté, le sélecteur représentant la méthode et les arguments de la méthode. Cela permet d'éviter d'avoir à  chercher dans le cache et/ou dans le pointeur isa la méthode à  exécuter.

    Il faut remarquer, cependant, que le cache permet de fortement accélérer l'envoie de message, car une fois un message exécuté celui-ci est caché et plus rapidement accessible. Selon Apple après le caching une exécution de méthode est pratiquement aussi rapide qu'un appel de fonction C. Mais ils recommandent tout de même l'utilisation d'un pointeur IMP dans le cas d'un traitement intensif du style boucle.

    Voilà , j'espère avoir éclairé ta lanterne. :D
  • Philippe49Philippe49 Membre
    septembre 2007 modifié #25
    dans 1190158640:


    Que fait objc_msgSend() ?
    Lorsque la fonction est exécutée, elle commence d'abord par vérifier si le message envoyé n'est pas déjà  dans un cache,
    Dans le cas où la méthode n'est pas cachée, donc qu'elle n'a jamais été exécutée, ...


    Oui, j'avais déjà  lu ce mécanisme.

    Si je le comprends bien, une méthode ayant déjà  été appelée est référencée dans un cache afin d'optimiser les appels ultérieurs à  cette méthode. Bien. Ce sera le cas pour rangeForCharactersFromSet:  options: range:
    Pourquoi l'optimisation de code n'aurait pas prévu ce cas, qui se reproduit dans quasiment toute méthode ?

    Je te livre un exemple d'optimisation que j'ai rencontré récemment :
    {
    int i,A;
    for(i=0;i<UNMILLIARD;i++)
      A=i;
    printf("au revoir");
    }

    ==> temps d'exécution = quasi nul
    gcc a été capable de voir que la boucle changeait A, mais que A n'était pas utilisé après. Elle a purement et simplement remplacer la boucle par i=UNMILLIARD !

    Donc, pour moi, le cas d'optimisation de code dont on parle a de fortes chances d'être prévu
    Je vais essayer de comparer les temps d'exécution ...

    dans 1190158640:

    Donc tu peux voir que l'envoie de message est un mécanisme complexe. Les pointeurs de méthodes que j'utilise en l'occurrence permettent de contourner ce système.


    hum ...
  • psychoh13psychoh13 Mothership Developer Membre
    20:30 modifié #26
    dans 1190180165:
    Oui, j'avais déjà  lu ce mécanisme.

    Si je le comprends bien, une méthode ayant déjà  été appelée est référencée dans un cache afin d'optimiser les appels ultérieurs à  cette méthode. Bien. Ce sera le cas pour rangeForCharactersFromSet:  options: range:
    Pourquoi l'optimisation de code n'aurait pas prévu ce cas, qui se reproduit dans quasiment toute méthode ?


    Ce n'est pas possible tout simplement parce que objc_msgSend() (et ses copines) est une fonction déjà  écrite et compilée dans la bibliothèque libobjc, donc pour elle les optimisations sont impossibles puisque le code est déjà  compilé (surtout qu'elle est écrite en assembleur car la construction des appels de fonctions et compliquées).

    Or, GCC lorsqu'il compile le code l ne fait que convertir le message en appel à  la fonction objc_msgSend() et tout est dynamique, comme GCC peut-il faire une optimisation à  ce niveau ?

    dans 1190180165:
    Donc, pour moi, le cas d'optimisation de code dont on parle a de fortes chances d'être prévu


    à‰tant donné le dynamisme du langage ce n'est pas possible de prévoir ça.

    dans 1190180165:
    Je vais essayer de comparer les temps d'exécution ...


    Il te faudra utiliser une méthode beaucoup plus complexe parce que la mienne est trop rapide pour permettre une comparaison saine.

    dans 1190180165:
    dans 1190158640:

    Donc tu peux voir que l'envoie de message est un mécanisme complexe. Les pointeurs de méthodes que j'utilise en l'occurrence permettent de contourner ce système.


    hum ...



    Oui oui ça contourne le système ! En tout cas, ça le contourne dans le cas du message que j'envoie plusieurs fois, bien sûr tu as toujours le methodForSelector: qu'il faut appeler.
  • Philippe49Philippe49 Membre
    20:30 modifié #27
    dans 1190118214:

    C'est moche ! ???


    et en plus c'est faux  >:( ??? ::)  :o ;D  ;D ;D :P (le dernier objet risque de ne pas être pris en compte)!!

    voilà  un code comme tu les aimes


    @implementation NSString (componentsSeparatedByCharactersFromString)
    -(NSArray *) componentsSeparatedByCharactersFromString:(NSString *) characters
    {
    NSScanner * scanner=[NSScanner scannerWithString:self];
    NSCharacterSet * charactersToBeSkipped=[NSCharacterSet characterSetWithCharactersInString:characters];
    NSMutableArray * array=[NSMutableArray array];
    NSString * current;
    BOOL founded;
    do {
    [scanner scanCharactersFromSet:charactersToBeSkipped intoString:nil];
    founded=[scanner scanUpToCharactersFromSet:charactersToBeSkipped intoString:&current];
    [array addObject:current];
    } while(founded);
    return [[array retain] autorelease];
    }
    @end
  • psychoh13psychoh13 Mothership Developer Membre
    20:30 modifié #28
    dans 1190183639:


    et en plus c'est faux  >:( ??? ::)  :o ;D  ;D ;D :P (le dernier objet risque de ne pas être pris en compte)!!

    voilà  un code comme tu les aimes


    @implementation NSString (componentsSeparatedByCharactersFromString)
    -(NSArray *) componentsSeparatedByCharactersFromString:(NSString *) characters
    {
    NSScanner * scanner=[NSScanner scannerWithString:self];
    NSCharacterSet * charactersToBeSkipped=[NSCharacterSet characterSetWithCharactersInString:characters];
    NSMutableArray * array=[NSMutableArray array];
    NSString * current;
    BOOL founded;
    do {
    [scanner scanCharactersFromSet:charactersToBeSkipped intoString:nil];
    founded=[scanner scanUpToCharactersFromSet:charactersToBeSkipped intoString:&current];
    [array addObject:current];
    } while(founded);
    return [[array retain] autorelease];
    }
    @end



    Ta méthode supprime les espaces qui sont end début de chaà®ne. :D
    Ensuite, ce truc : return [[array retain] autorelease]; sert à  rien :D
    Tu peux faire : return array; directement parce que l'objet reçoit l'autorelease directement grâce à  la méthode -array et étant donné que tu n'utilises pas d'autorelease pool dans ta méthode, tu insères deux fois le même objet pour une seule utilisation. :D
    Enfin, c'est pas grave parce que c'est un autorelease mais bon... :D
  • Philippe49Philippe49 Membre
    20:30 modifié #29
    dans 1190184776:

    Ta méthode supprime les espaces qui sont end début de chaà®ne. :D


    oui c'était dans la définition de la méthode

    dans 1190183639:

    c'est moche et en plus c'est faux 

    Non, la première méthode était juste, car scanUpToCharactersFromSet: intoString: renvoie YES lorsqu'il scanne des caractères , ce qu'il fait en arrivant en bout de chaà®ne.
    Par la contre la deuxième avec le booléen, elle, elle coince en bout de chaà®ne ...

    dans 1190180165:



    Je vais essayer de comparer les temps d'exécution ...


    c'est sans appel :

    3 fois plus de temps pour ma méthode.
    Par contre les deux tiennes sont à  peu près équivalentes.
    Il resterait à  tester une fonction C pure

    dans l'ordre : la mienne , les deux tiennes
    (les différences de résultats s'expliquent puisque l'on n'a pas traité de la même façon les extrémités de la chaà®ne)


    le code d'essai :
    <br />/* Compiler&nbsp; ainsi<br />	% gcc -O3 mypgm.m -o mypgm -framework Foundation<br />*/<br />#import &lt;Cocoa/Cocoa.h&gt;<br /><br />@interface NSString (componentsSeparatedByCharactersFromString)<br />-(NSArray *) componentsSeparatedByCharactersFromString:(NSString *) characters;<br />@end<br /><br />/*@interface NSString (NSStringPSYAdds)<br />-(NSArray *) componentsSeparatedByCharacters:(NSCharacterSet *) aSet;<br />@end<br />*/<br />int main(int argc, char * argv&#91;] ){<br />	NSAutoreleasePool * pool=[NSAutoreleasePool new];<br />//	NSCharacterSet * charactersToBeSkipped=[NSCharacterSet characterSetWithCharactersInString:@&quot;(,) &quot;];<br />	NSMutableString * string=[NSMutableString stringWithString:@&quot;(NSRange (*)(id, SEL, NSCharacterSet*, unsigned int, NSRange))[self methodForSelector:rangeOfCharSel&quot;];<br />	int i,compt=0,len=[string length];<br />	NSRange range;<br />	range.length=1;<br />	for(i=0;i&lt;100000;i++){<br />		range.location=i % len;<br />		[string replaceCharactersInRange:range withString:[NSString stringWithFormat:@&quot;%c&quot;,32+(2*i)%70]];<br />		NSArray * array=[string componentsSeparatedByCharactersFromString:@&quot;(,) &quot;] ;<br />		compt+=[array count]%2;<br />		}<br />	printf(&quot;&#092;nNombre de cas impairs : %d&#092;n&quot;,compt);	<br />	[pool release];<br />}<br /><br />@implementation NSString (componentsSeparatedByCharactersFromString)<br />-(NSArray *) componentsSeparatedByCharactersFromString:(NSString *) characters<br />{<br />	NSScanner * scanner=[NSScanner scannerWithString:self];<br />	NSCharacterSet * charactersToBeSkipped=[NSCharacterSet characterSetWithCharactersInString:characters];<br />	NSMutableArray * array=[NSMutableArray array];<br />	NSString * current;<br />	while( [scanner scanCharactersFromSet:charactersToBeSkipped intoString:nil],[scanner scanUpToCharactersFromSet:charactersToBeSkipped intoString:&amp;current]){<br />		[array addObject:current];<br />	} <br />	return [[array retain] autorelease];<br />}<br />@end <br /><br />/*<br /><br />Voilà , je me suis amusé à  faire cette méthodes qu&#39;a indiqué Philippe49.<br /><br />J&#39;en ai fait deux implémentations en Objective-C, la première, la plus simple, utilisant l&#39;envoie de message normal, et la deuxième, optimisée, qui utilise les pointeurs de méthodes et les imps :<br /><br />Première implémentation :<br />*/<br /><br />/*<br />@implementation NSString (NSStringPSYAdds)<br />-(NSArray *) componentsSeparatedByCharacters:(NSCharacterSet *) aSet<br />{<br />NSMutableArray *strings = [NSMutableArray array];<br />unsigned strLength = [self length];<br /> <br />NSRange<br />verifyRange = NSMakeRange(0, strLength),<br />resultRange = NSMakeRange(0, 1),<br />subRange = NSMakeRange(0, -1);<br /><br />resultRange = [self rangeOfCharacterFromSet:aSet options:NSLiteralSearch range:verifyRange];<br /> <br />while(resultRange.location != NSNotFound &amp;&amp; resultRange.location != strLength)<br />{<br />subRange.location = verifyRange.location;<br />subRange.length = resultRange.location - verifyRange.location;<br /><br />[strings addObject:[self substringWithRange:subRange]];<br /><br />verifyRange.location = subRange.location + subRange.length + 1;<br />verifyRange.length = strLength - verifyRange.location;<br /><br />resultRange = [self rangeOfCharacterFromSet:aSet options:NSLiteralSearch range:verifyRange];<br />}<br /><br />[strings addObject:[self substringWithRange:verifyRange]];<br /><br />return strings;<br />}<br /><br />@end<br />*/<br /><br />/*<br />@implementation NSString (NSStringPSYAdds)<br />-(NSArray *) componentsSeparatedByCharacters:(NSCharacterSet *) aSet<br />{<br />NSMutableArray *strings = [NSMutableArray array];<br />unsigned strLength = [self length];<br /><br />// Paperasse nécessaire pour utiliser les implémentations<br />// On doit garder le sélecteur pour le passer en deuxième argument<br />SEL rangeOfCharSel = @selector(rangeOfCharacterFromSet:options:range:);<br /><br />// On définit un pointeur de fonction spécifique, c&#39;est ce qui est conseillé par Apple<br />NSRange (*rangeOfCharImp)(id, SEL, NSCharacterSet*, unsigned int, NSRange) =(NSRange (*)(id, SEL, NSCharacterSet*, unsigned int, NSRange))[self methodForSelector:rangeOfCharSel];<br />// C&#39;est moche mais c&#39;est un simple cast pour éviter d&#39;avoir un warning<br /><br /><br />SEL substringSel = @selector(substringWithRange:);<br />NSString *(*substringImp)(id, SEL, NSRange) =(NSString *(*)(id, SEL, NSRange))[self methodForSelector:substringSel];<br /><br />SEL addObjectSel = @selector(addObject:);<br />void (*addObjectImp)(id, SEL, id) =(void (*)(id, SEL, id))[strings methodForSelector:addObjectSel];<br /><br />NSRange<br />	verifyRange = NSMakeRange(0, strLength),<br />	resultRange = NSMakeRange(0, 1),<br />	subRange = NSMakeRange(0, -1);<br /><br />resultRange = rangeOfCharImp(self, rangeOfCharSel, aSet, NSLiteralSearch, verifyRange);<br /><br />while(resultRange.location != NSNotFound &amp;&amp; resultRange.location != strLength)<br />{<br />subRange.location = verifyRange.location;<br />subRange.length = resultRange.location - verifyRange.location;<br /><br />addObjectImp(strings, addObjectSel, substringImp(self, substringSel, subRange));<br /><br />verifyRange.location = subRange.location + subRange.length + 1;<br />verifyRange.length = strLength - verifyRange.location;<br /><br />resultRange = rangeOfCharImp(self, rangeOfCharSel, aSet, NSLiteralSearch, verifyRange);<br />}<br /><br />addObjectImp(strings, addObjectSel, substringImp(self, substringSel, verifyRange));<br /><br />return strings;<br />}<br /><br />@end<br /><br />*/<br />
    




    [Fichier joint supprimé par l'administrateur]
  • psychoh13psychoh13 Mothership Developer Membre
    septembre 2007 modifié #30
    C'est normal que ta méthode soit moins efficace que la mienne, tu utilises un objet et des méthodes qui, pour fonctionner, nécessite d'utiliser un objet d'une autre classe, les envoies de messages doivent être nombreux dans NSScanner. D'ailleurs il faudrait vérifier qu'il n'y ait pas de fuite mémoire dans ta méthode... (la string scannée est-elle autoreleasée ??)
  • Philippe49Philippe49 Membre
    20:30 modifié #31
    dans 1190189353:

    C'est normal que ta méthode soit moins efficace que la mienne, tu utilises un objet et des méthodes qui, pour fonctionner, nécessite d'utiliser un objet d'une autre classe, les envois de messages doivent être nombreux dans NSScanner.

    oui

    dans 1190189353:

    D'ailleurs il faudrait vérifier qu'il n'y ait pas de fuite mémoire dans ta méthode... (la string scannée est-elle autoreleasée ??)

    Il me semble : une "convenient method" comme scannerWithString: crée le scanner en autorelease.
    Par contre, en forçant le nombre de boucles dans le test, je tombe sur un manque de mémoire qui est sans doute dû au fait que la libération de la mémoire des objets en autorelease sont réalisés en lazy-mode. Cela confirme le post de Bru.

    dans 1190184776:

    Ensuite, ce truc : return [[array retain] autorelease]; sert à  rien :D

    Tout à  fait d'accord.
    J'avais été surpris de le trouver dans le script Apple "Place Accessor Defs On Clipboard" (menu des scripts de XCode), alors un peu de provoque ...


    Merci pour cette discusion



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