[Résolu] Utilisation des catégories...

Alf1996Alf1996 Membre
mai 2013 modifié dans API UIKit #1

En plein ménage dans mon code, je me rend compte que j'avais dupliqué une méthode dont j'avais besoin dans deux classes différentes !  >:)


En cherchant un peu, j'ai réalisé que cette méthode pouvait être déclarée dans une catégorie sur NSString.


J'ai fait ceci, dans NSString+MyStringCategory.h :



//
#import <Foundation/Foundation.h>

@interface NSString (MyStringCategory)
-(BOOL) wordsExist:(NSArray *)listOfWords;

@end


et dans NSString+MyStringCategory.m :




#import "NSString+MyStringCategory.h"

@implementation NSString (MyStringCategory)

-(BOOL) wordsExist:(NSArray *)listOfWords {
// Teste si l'un des mots du NSArray listOfWords est présent dans la string
BOOL boolToReturn=NO;
for (int ii=0; ii<[listOfWords count]; ii++) {
boolToReturn=boolToReturn || ([self rangeOfString:[listOfWords objectAtIndex:ii]].location!=NSNotFound);
}
return boolToReturn;
}

J'ai testé, çà  fonctionne très bien, et j'ai un peu allégé mon code. Maintenant, j'ai une autre méthode, dont j'aurais également besoin dans plusieurs classes différentes, et qui traite également des NSString, et je me demande si je peux aussi la mettre dans une catégorie... ou s'il y a une autre solution plus adaptée.


Il s'agit d'une méthode qui extrait le premier mot d'une NSString, et qui le retire de la dite NSString. Pour pouvoir modifier la string, j'ai donc passé son adresse. 



-(NSString *) extractWord:(NSString **)line;


si line vaut @Ceci est une chaine de caractères, la méthode va retourner @Ceci, et line deviendra @est une chaine de caractères.


 


Je me demande donc si l'utilisation d'une catégorie est adaptée dans ce cas. Merci d'avance pour vos lumières.   o:)


 


 


Réponses

  • jpimbertjpimbert Membre
    avril 2013 modifié #2


    Maintenant, j'ai une autre méthode, dont j'aurais également besoin dans plusieurs classes différentes, et qui traite également des NSString, et je me demande si je peux aussi la mettre dans une catégorie... ou s'il y a une autre solution plus adaptée.


    Il s'agit d'une méthode qui extrait le premier mot d'une NSString, et qui le retire de la dite NSString. Pour pouvoir modifier la string, j'ai donc passé son adresse. 


     


    -(NSString *) extractWord:(NSString **)line;

     


    si line vaut @Ceci est une chaine de caractères, la méthode va retourner @Ceci, et line deviendra @est une chaine de caractères.


     


    Je me demande donc si l'utilisation d'une catégorie est adaptée dans ce cas. Merci d'avance pour vos lumières.    o:)


     


    Ce serait plus logique que ce soit une catégorie de NSMutableString


  • +1 pour le NSMutableString.


     


    Si tu permets une suggestion, vu que tu es dans la révision de ton code, j'aurai imaginé dans ta methode wordsExist: soit une boucle du style :



    for (NSString *string in listOfWords) {
    ...
    }

     


    ou alors carrément :


     



    NSUInteger index = [listOfWords indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    if ([self rangeOfString:obj].location != NSNotFound {
    *stop = YES;
    return YES;
    }
    return NO;
    }];

     


    Ca peut valoir le coup selon la taille de ton tableau.


  •  


    Ce serait plus logique que ce soit une catégorie de NSMutableString

     


    Evidemment...


     


    +1 pour le NSMutableString.


     


    Si tu permets une suggestion, vu que tu es dans la révision de ton code, j'aurai imaginé dans ta methode wordsExist: soit une boucle du style :



    for (NSString *string in listOfWords) {
    ...
    }

     


    ou alors carrément :


     



    NSUInteger index = [listOfWords indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    if ([self rangeOfString:obj].location != NSNotFound {
    *stop = YES;
    return YES;
    }
    return NO;
    }];

     


    Ca peut valoir le coup selon la taille de ton tableau.


     


    Merci, effectivement je vais utiliser le première solution, mes NSArray ne contiennent pas des grandes quantités d'items (tout au plus 5 ou 6), çà  fait plus propre. Je garde quand même la deuxième solution au cas où...


    Concernant ma méthode à  mettre en catégorie de NSMutableString, je me posais surtout la question de savoir si je pourrai faire  :



    myFirstWord=[myMutableString extractWord];
     

     


    ou myFirstWord sera un NSString et le contenu de myMutableString sera modifié, ou alors devrais-je appeler la méthode en passant l'adresse de myMutableString?


    Ou encore, ai-je le droit de faire, dans la catégorie :



    NSString *theFirstWord=[self substringToIndex:index];
    self=[self substringFromIndex:index+1];
    return theFirstWord;

    index étant le NSRange du premier séparateur de mot (espace ou tiret).


     


    Merci pour les conseils

  • mpergandmpergand Membre
    avril 2013 modifié #5

    Une catégorie sur NSScanner ?


     



    @implementation NSScanner (CTScanner)

    -(NSString*) nextWord
    {
    NSString* str=nil;

    [self scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:&str];

    return str;

    }

    -(NSString*) stringFromLocation
    {
    return self string] substringFromIndex:[self scanLocation;

    }


    /* */
    NSString* essai=@Il fait beau aujourd'hui ?;

    NSScanner* scanner=[NSScanner scannerWithString:essai];

    NSString* word;

    while((word=[scanner nextWord]))
    {
    NSLog(@%@ - %@",word,[scanner stringFromLocation]);

    }

    // logs:
    Il - fait beau aujourd'hui ?
    fait - beau aujourd'hui ?
    beau - aujourd'hui ?
    aujourd'hui - ?
    ? -




  • jpimbertjpimbert Membre
    avril 2013 modifié #6

    myFirstWord = [myMutableString extractWord];

     


    est tout à  fait légitime.


     


    Deux recommandations :


    - indiquer dans la documentation que le destinataire du message est modifié ;


    - appeler la méthode extractFirstWord.


  • Une catégorie sur NSScanner ?


     



    @implementation NSScanner (CTScanner)

    -(NSString*) nextWord
    {
    NSString* str=nil;

    [self scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:&str];

    return str;

    }

    -(NSString*) stringFromLocation
    {
    return self string] substringFromIndex:[self scanLocation;

    }


    /* */
    NSString* essai=@Il fait beau aujourd'hui ?;

    NSScanner* scanner=[NSScanner scannerWithString:essai];

    NSString* word;

    while((word=[scanner nextWord]))
    {
    NSLog(@%@ - %@",word,[scanner stringFromLocation]);

    }

    // logs:
    Il - fait beau aujourd'hui ?
    fait - beau aujourd'hui ?
    beau - aujourd'hui ?
    aujourd'hui - ?
    ? -




    Pas mal comme solution... Je n'utilisais pas NSScanner jusqu'à  présent. Je vais me pencher dessus !


     


    Merci à  tous pour votre aide.

  • AliGatorAliGator Membre, Modérateur

    Concernant ma méthode à  mettre en catégorie de NSMutableString, je me posais surtout la question de savoir si je pourrai faire  :



    myFirstWord=[myMutableString extractWord];  

     


    ou myFirstWord sera un NSString et le contenu de myMutableString sera modifié


    Oui ça me parait parfait ça.


     


    ou alors devrais-je appeler la méthode en passant l'adresse de myMutableString?


    Pas besoin de passer l'adresse puisque c'est une catégorie sur NSMutableString tu auras la chaà®ne en question dans "self", comme tu l'as compris vu tes exemples d'ailleurs. Donc pourquoi se compliquer la vie et vouloir passer son adresse alors que tu l'as déjà  ? ;)


     


    Ou encore, ai-je le droit de faire, dans la catégorie :



    NSString *theFirstWord=[self substringToIndex:index];
    self=[self substringFromIndex:index+1];
    return theFirstWord;

    Je te déconseille fortement de réaffecter "self" en dehors des méthodes d'init.


    Tu fais justement une méthode sur NSMutableString donc tu vas pouvoir directement modifier le contenu de self (et pas le réaffecter)


     


    -(NSString*)popFirstWord
    {
      NSString* foundWord = nil;
      NSRange r = [self rangeOfCharacterFromSet: [NSCharacterSet whitespaceAndNewlineCharacterSet] ];
      if (r.location != NSNotFound)
      {
        // Espace trouvé : extraire le texte avant, et le supprimer
        foundWord = [self substringToIndex:r.location];
        [self deleteCharactersInRange: NSMakeRange(0, NSMaxRange(r))]; // supprimer du caractère 0 jusqu'à  l'espace trouvé, inclus.
      }
      else
      {
        // Aucun espace trouvé, donc il doit sans doute ne rester qu'un seul mot : vider la chaà®ne et retourner ce mot
        foundWord = [[self copy] autorelease];
        [self setString:@""];
      }
      return foundWord;
    }
  • Super...


    Sur le principe, c'est exactement ce que j'imaginais !


    Le seul détail, c'est que mes mots peuvent être séparés soit pas des espaces (ou sauts de ligne, avec parfois plusieurs espaces !), soit par des tirets (-), soit par les deux  B)


    Je dois pouvoir adapter le NSCharacterSet en y ajoutant le tiret, mais alors que se passera-t-il si j'ai une chaine du style :


    mot1 mot2  -  mot3 mot4.... ?


     


    Merci


     


  • AliGatorAliGator Membre, Modérateur

    Pour les tirets, tu peux créer un NSMutableCharacterSet à  base de whitespaceAndNewlineCharacterSet et lui ajouter ensuite le tiret.


    (Ca vaut sans doute le coup de ne le construire que la première fois et le garder de côté, dans une variable static, plutôt que le construire à  chaque fois ?)


     


    Pour les cas où ta chaà®ne contient plusieurs espaces et/ou tirets à  la suite, il suffit dans la méthode popFirstWord d'encapsuler tout le code dans une boucle "while( foundWord.length<=0 && self.length>0)" pour que tant qu'il trouve un premier mot "vide" (parce que 2 espaces à  la suite), il recommence, jusqu'à  en trouver un de longueur minimum 1... ou que la chaà®ne soit vide et qu'il ne trouve plus aucun mot.


  • Génial, merci infiniment


    Je testerai çà  ce soir


  • AliGatorAliGator Membre, Modérateur

    Oui d'ailleurs je te laisse adapter et tester, j'ai pas testé le code en vrai hein ;)


  • Alf1996Alf1996 Membre
    avril 2013 modifié #13

    Oui d'ailleurs je te laisse adapter et tester, j'ai pas testé le code en vrai hein ;)


     


    Pas de problème... Tu en as déjà  fait beaucoup quand même. Je ne vais tout de même pas te demander de tester et de l'intégrer dans mon projet en plus !!!  ;)


  • Désolée pour le délai mais j'ai eu peu de temps à  passer sur Xcode ces temps ci et en plus, les modifications étaient assez lourdes car les méthodes à  remplacer sont assez souvent utilisées !


    Voila ce que j'ai finalement fait et qui fonctionne correctement ; en fait j'ai créé deux méthodes similaires car j'avais aussi besoin d'une méthode qui extrait les lignes :


     


    .h



    //

    #import <Foundation/Foundation.h>

    @interface NSMutableString (MyCategory)

    -(NSString *) extractFirstWord;
    -(NSMutableString *) extractFirstLine;

    @end


    .m



    //

    #import "NSMutableString+MyCategory.h"


    @implementation NSMutableString (MyCategory)

    -(NSString *) extractFirstWord {
    NSCharacterSet *charSet = [NSCharacterSet characterSetWithCharactersInString:@\n\t -];
    NSString* foundWord = nil;
    while (foundWord.length<=0 && self.length>0) {
    NSRange r = [self rangeOfCharacterFromSet: charSet ];
    if (r.location != NSNotFound) {
    // il y a un espace (ou saut de ligne/tab/tiret) - extraction du mot
    foundWord = [self substringToIndex:r.location];
    [self deleteCharactersInRange: NSMakeRange(0, NSMaxRange(r))];
    } else {
    // pas de séparateur trouvé - c'est le dernier mot
    foundWord = [[self copy] autorelease];
    [self setString:@""];
    }
    }
    return foundWord;
    }

    -(NSMutableString *) extractFirstLine {
    NSMutableString* foundLine = nil;
    while (foundLine.length<=0 && self.length>0) {
    NSRange r = [self rangeOfCharacterFromSet: [NSCharacterSet newlineCharacterSet] ];
    if (r.location != NSNotFound) {
    // il y a un saut de ligne - extraction puis suppression de la ligne
    foundLine = [[self substringToIndex:r.location] mutableCopy];
    [self deleteCharactersInRange: NSMakeRange(0, NSMaxRange(r))];
    } else {
    // pas de saut de ligne - c'est la dernière ligne
    foundLine = [[self copy] autorelease];
    [self setString:@""];
    }
    }
    return foundLine;
    }

    @end


    Mon problème se situe maintenant au niveau du CharacterSet. Pour l'instant je le créée de la façon suivante :



    NSCharacterSet *charSet = [NSCharacterSet characterSetWithCharactersInString:@\n\t -];


    Mais vu que j'utilise assez souvent cette méthode, cela revient à  créer une instance à  chaque passage, c'est bien çà  ? Donc une empreinte mémoire qui risque d'augmenter ?


    Ali m'avait conseillé d'utilisé une variable static, créée à  partir d'un NSMutableCharacterSet, et je me demande pourquoi "Mutable". Ne puis-je pas définir ma variable static à  partir de "charset" ?


     


    Merci d'avance 


  • mpergandmpergand Membre
    avril 2013 modifié #15

     


    Ali m'avait conseillé d'utilisé une variable static, créée à  partir d'un NSMutableCharacterSet, et je me demande pourquoi "Mutable". Ne puis-je pas définir ma variable static à  partir de "charset" ?

     


    Non pas de problème.


     


    static NSCharacterSet* sFirstWordCharacterSet;


     


    En fait le problème c'est pour l'initialiser, normalement on peut utiliser initialize, mais dans une catégorie ...



    +(void) initialize
    {
    sFirstWordCharacterSet=[[NSCharacterSet characterSetWithCharactersInString:@\n\t -] retain];
    }

    Sinon, il faudra que tu testes au début de ta méthode pour le créer si la variable static est nil.


  • Ok merci, je étudier çà  d'un peu plus près demain...


  • Un truc comme ça peut être ? En plus ça permet d'avoir quelque chose de flexible, d'éviter de dupliquer le code et de garder qu'une seule instance du characterSet.



    -(NSString *) extractFirstWord
    {
    return [self extractCharactersInString:@\n\t -];
    }

    -(NSMutableString *) extractCharactersInString:(NSString *) extractString
    {
    static NSMutableCharacterSet *characterSet;
    static NSString *string;
    if (characterSet == nil) {
    characterSet = [[NSMutableCharacterSet alloc] init];
    }
    [characterSet removeCharactersInString:string];
    [characterSet addCharactersInString:extractString];
    string = extractString;

    NSMutableString* foundCharacters = nil;

    while (foundCharacters.length <= 0 && self.length>0) {
    NSRange r = [self rangeOfCharacterFromSet: characterSet];
    if (r.location != NSNotFound) {
    foundCharacters = [[self substringToIndex:r.location] mutableCopy];
    [self deleteCharactersInRange: NSMakeRange(0, NSMaxRange(r))];
    } else {
    foundCharacters = [[self copy] autorelease];
    [self setString:@""];
    }
    }
    return foundCharacters;
    }

  • @JegnuX : Génial ton truc, çà  fonctionne très bien.


    Merci infiniment à  tous pour votre aide.


     


    Le code final :


     



    -(NSString *) extractFirstWord {
    return [self extractCharacterInString:@\n\t -];
    }

    -(NSMutableString *) extractFirstLine {
    return [self extractCharacterInString:@\n];
    }

    -(NSMutableString *) extractCharacterInString:(NSString *)extractString {
    static NSMutableCharacterSet *charSet;
    static NSString *string;
    if (charSet == nil) {
    charSet = [[NSMutableCharacterSet alloc] init];
    }
    [charSet removeCharactersInString:string];
    [charSet addCharactersInString:extractString];
    string=extractString;

    NSMutableString* foundCharacters = nil;
    while (foundCharacters.length<=0 && self.length>0) {
    NSRange r = [self rangeOfCharacterFromSet: charSet ];
    if (r.location != NSNotFound) {
    // il y a une occurence du charSet - extraction puis suppression des caractères extraits
    foundCharacters = [[self substringToIndex:r.location] mutableCopy];
    [self deleteCharactersInRange: NSMakeRange(0, NSMaxRange(r))];
    } else {
    // pas d'ocurence de charSet - c'est le dernier paquet de caractères
    foundCharacters = [[self copy] autorelease];
    [self setString:@""];
    }
    }
    return foundCharacters;

    }


  • De rien :)


    Par contre en relisant j'ai l'impression qu'il manque un autorelease sur le substring/mutableCopy.


    Et tant qu'à  faire mettre aussi NSMutableString en type de retour de extractFirstWord


     


    Et aussi, -extractCharacterInString: correspond pas trop. J'aurais du mettre un truc comme -extractCharactersSeparatedByCharactersInString: (plus long mais qui indique mieux ce que ça fait)


     


    Bon j'arrête de chipoter. ^^'


  • AliGatorAliGator Membre, Modérateur

    Je le trouve bizarre ce code et surtout l'utilisation du static...


    Tu n'initialises ton NSMutableCharacterSet qu'une seule fois... mais ce même NSMCS tu le modifies selon les paramètres passés à  la méthode. Ce qui fait que la première fois que tu appelles la méthode, ton NSMCS est nil et il est du coup créé, puis tu en retires tous les caractères présents dans ta chaà®ne string et rajoutes tous les caractères présents dans le paramètre.


     


    Au second appel, la NSMCS n'est plus nil... mais elle a déjà  été modifiée par le premier appel. Du coup les appels successifs à  ta méthode dépendent des appels précédents. Ta méthode n'est plus déterministe (comportement déterministe = pour une entrée donnée tu as toujours la même sortie en résultat, ce n'est donc pas le cas ici car ça dépend des appels précédents) et en plus tu n'as aucun moyen de la remettre à  zéro.


     


    Donc si tu crées une NSMutableString "toto tata titi", appelle ta méthode extractFirstWord (qui va créer ton NSMCS et le modifier dès le premier appel) une voire 2 fois... puis fait un [mutStr setString:@toto tata toto] pour réinitialiser/changer le contenu de ta NSMutableString et que tu rappelles extractFirstWord dessus... ton NSMCS ne sera pas réinitialisé, sera encore dans l'état dans lequel il a été laissé après les 2 appels à  extractFirstWord précédents, et extractFirstWord risque de ne pas retourner la même chose que la première fois où tu avais "toto tata titi" dans ta chaà®ne...


     


    Bref, pas très logique tout ça...



  • Je le trouve bizarre ce code et surtout l'utilisation du static...

    Tu n'initialises ton NSMutableCharacterSet qu'une seule fois... mais ce même NSMCS tu le modifies selon les paramètres passés à  la méthode. Ce qui fait que la première fois que tu appelles la méthode, ton NSMCS est nil et il est du coup créé, puis tu en retires tous les caractères présents dans ta chaà®ne string et rajoutes tous les caractères présents dans le paramètre.

     

    Au second appel, la NSMCS n'est plus nil... mais elle a déjà  été modifiée par le premier appel. Du coup les appels successifs à  ta méthode dépendent des appels précédents. Ta méthode n'est plus déterministe (comportement déterministe = pour une entrée donnée tu as toujours la même sortie en résultat, ce n'est donc pas le cas ici car ça dépend des appels précédents) et en plus tu n'as aucun moyen de la remettre à  zéro.

     

    Donc si tu crées une NSMutableString "toto tata titi", appelle ta méthode extractFirstWord (qui va créer ton NSMCS et le modifier dès le premier appel) une voire 2 fois... puis fait un [mutStr setString:@toto tata toto] pour réinitialiser/changer le contenu de ta NSMutableString et que tu rappelles extractFirstWord dessus... ton NSMCS ne sera pas réinitialisé, sera encore dans l'état dans lequel il a été laissé après les 2 appels à  extractFirstWord précédents, et extractFirstWord risque de ne pas retourner la même chose que la première fois où tu avais "toto tata titi" dans ta chaà®ne...

     

    Bref, pas très logique tout ça...



     

    Je vois pas bien le soucis ? Je réinitialise bien mon NSMCS à  chaque passage. C'est juste que je ne fait pas un nouvel alloc/init

     

    Si tu regardes bien : 



    -(NSMutableString *) extractCharactersSeparatedByCharactersInString:(NSString *)extractString {
    static NSMutableCharacterSet *charSet; //Le charset en static pour n'avoir qu'une seule instance
    static NSString *string; //Une static qui permet de mémoriser quels characters avaient été ajouté au précédent appel.

    if (charSet == nil) { // On instancie le NSMCS au premier passage
    charSet = [[NSMutableCharacterSet alloc] init];
    }
    [charSet removeCharactersInString:string]; // On reset le NSMCS
    [charSet addCharactersInString:extractString]; // On ajoute les characters qu'on veut utiliser
    string=extractString; // On mémorise ces characters pour pouvoir reset au prochain passage

    ...


    Par contre oui on pourrait optimiser comme ceci : 



    -(NSMutableString *) extractCharactersSeparatedByCharactersInString:(NSString *)extractString {
    static NSMutableCharacterSet *charSet;
    static NSString *string;
    if (charSet == nil) {
    charSet = [[NSMutableCharacterSet alloc] init];
    }
    if ([extractString isEqualToString:string] == NO) {
    [charSet removeCharactersInString:string];
    [charSet addCharactersInString:extractString];
    string=extractString;
    }
  • AliGatorAliGator Membre, Modérateur

    Ah ouais en fait j'avais pas compris la logique bizarre de ta fonction... C'était pas clair à  la lecture du code cette utilisation de ta variable string (d'autant que le nom un peu générique n'aide pas ^^). Bon ok j'avais pas trop lu les commentaires, mais en mm temps normalement y'a pas besoin d'avoir à  les lire :P


     


    Pourquoi mémoriser la chaà®ne juste pour l'utiliser à  l'appel précédent pour réinitialiser ? Pourquoi ne pas plutôt reset le NSMCS à  la fin pour être totalement stateless ?


     


    -(NSMutableString *) extractCharactersSeparatedByCharactersInString:(NSString *)extractString
    {
        static NSMutableCharacterSet *charSet;
        if (charSet == nil) { // On instancie le NSMCS au premier passage 
            charSet = [[NSMutableCharacterSet alloc] init];
        }
        [charSet addCharactersInString:extractString]; // On ajoute les characters qu'on veut utiliser
    ...

        [charSet removeCharactersInString:extractString]; // On reset le NSMCS pour le prochain passage
    }
  • Ah ouais en fait j'avais pas compris la logique bizarre de ta fonction... C'était pas clair à  la lecture du code cette utilisation de ta variable string (d'autant que le nom un peu générique n'aide pas ^^). Bon ok j'avais pas trop lu les commentaires, mais en mm temps normalement y'a pas besoin d'avoir à  les lire :P

    Normal que tu n'avais pas vu les commentaires, il n'y en avait pas dans mon premier post.

    Pourquoi mémoriser la chaà®ne juste pour l'utiliser à  l'appel précédent pour réinitialiser ? Pourquoi ne pas plutôt reset le NSMCS à  la fin pour être totalement stateless ?
     
     

    -(NSMutableString *) extractCharactersSeparatedByCharactersInString:(NSString *)extractString
    {
        static NSMutableCharacterSet *charSet;
        if (charSet == nil) { // On instancie le NSMCS au premier passage 
            charSet = [[NSMutableCharacterSet alloc] init];
        }
        [charSet addCharactersInString:extractString]; // On ajoute les characters qu'on veut utiliser
    ...

        [charSet removeCharactersInString:extractString]; // On reset le NSMCS pour le prochain passage
    }


    Parce que je n'y avait pas pensé en fait >_< Mais oui, c'est bien plus élégant. Pour rappel, j'avais écris l'autre code à  1h du matin et je suis un petit joueur moi, ça fait trop longtemps que j'ai pas fait de nocturne :P

    Bon par contre, ptet un warning pour Alf : ce code n'est pas du tout thread-safe à  priori, donc fait attention ;)
  • AliGatorAliGator Membre, Modérateur

    Oui, honnêtement, entre garder le MCS en static pour ne l'allouer qu'une fois, mais perdre l'aspect thread-safe au passage et devoir le reset à  chaque fois... ou devoir faire un "alloc" à  chaque appel, franchement l'avantage d'utiliser un static ici est très discutable.


     


    Ca vaudrait le coup si tu avais à  le configurer une fois pour toute et ne plus y toucher (si les caractères à  utiliser comme séparateurs étaient fixes et pas passés en paramètre au risque d'être différents à  chaque fois), mais là  vu qu'à  chaque appel tu risques de le remodifier ça vaut pas le coup.


  • Ou alors, et là  ça commence à  être un peu le bordel, au lieu de faire un MCS en static, on peut mettre un NSMutableDictionary en static, avec en key le "extractString" et en value le NSCharacterSet associé (que l'on créé si besoin).
  • AliGatorAliGator Membre, Modérateur

    Ouais c'est possible... mais là  c'est prendre le bulldozer pour tuer une mouche !


     


    Et en plus si tu appelles 500 fois la méthode à  chaque fois avec un paramètre différent, tu auras un NSMutableDict de 500 entrées, et donc 500 instances de NSMCS et la mémoire qui va gonfler et ne sera jamais libérée.


     


    Et puis si tu veux vraiment faire un truc comme ça pour vraiment limiter les allocations, n'utilise pas un NSMutableDictionary. Utilise un NSCache. Bien plus efficace surtout que ça se libère tout seul quand il n'y a plus de mémoire (ou quand tu passes l'appli en background, etc), ça permet de soulager ton empreinte mémoire.


     


    Mais bon de toute façon pour si peu je conseille pas forcément cette approche d'avoir une méthode de catégorie et de garder en cache les NSMCS. Je préconise d'avoir un objet splitter dédié, à -la-NSScanner.


    Une méthode qu'on doit rappeler plusieurs fois pour boucler mais qui prend un paramètre (les caractères séparateurs), qui doit absolument être toujours le même quand on appelle en boucle pour découper notre chaà®ne sous peine d'avoir des comportements bizarres ou pas cohérents, c'est pas logique. Faut mieux initialiser un objet qui prend ce paramètre des caractères séparateurs et le stocke, et propose une autre méthode, elle à  appeler à  chaque itération.


  • Désolée, je ne peux pas tester vos solutions pour l'instant, je suis en vacances dans un trou paumé... et juste l'iPhone pour répondre. Merci pour toutes ces informations 


  • Bon, çà  y est, je suis de retour... et j'ai bien étudié vos remarques.


    Le fait que la solution ne soit pas thread-safe n'est pas gênante dans mon projet actuel, mais comme je souhaite pouvoir éventuellement réutiliser la catégorie, je vais tout de même éviter !


     


     




    De rien :)


    Par contre en relisant j'ai l'impression qu'il manque un autorelease sur le substring/mutableCopy.


    Et tant qu'à  faire mettre aussi NSMutableString en type de retour de extractFirstWord


     


    Et aussi, -extractCharacterInString: correspond pas trop. J'aurais du mettre un truc comme -extractCharactersSeparatedByCharactersInString: (plus long mais qui indique mieux ce que ça fait)


     


    Bon j'arrête de chipoter. ^^'




     


    C'est bien un NSString dont j'ai besoin pour le retour de extractFirstWord, car je n'ai plus de traitement à  faire sur le résultat, alors que lorsque j'extrais une ligne, il es possible que j'aie besoin de la découper...


     


    Voici mon code final de la catégorie, qui a l'air de fonctionner correctement. Qu'en pensez vous ?


    En particulier, j'ai dû faire un retain sur mes deux statics, et je me demande quand je dois les libérer... Probablement à  la fin de l'application, mais est-ce possible ? çà  me gêne un peu, mais je ne vois pas comment faire autrement !


    -(NSString *) extractFirstWord {
        static NSCharacterSet* sWordSeparatorCharacterSet;
        if (sWordSeparatorCharacterSet==nil) {
            sWordSeparatorCharacterSet=[[NSCharacterSet characterSetWithCharactersInString:@\n\t -] retain];
        }
        return [NSString stringWithString:[self  extractCharactersSeparatedByCharactersInString:sWordSeparatorCharacterSet]];
    }
     
    -(NSMutableString *) extractFirstLine {
        static NSCharacterSet* sLineSeparatorCharacterSet;
        if (sLineSeparatorCharacterSet==nil) {
            sLineSeparatorCharacterSet=[[NSCharacterSet characterSetWithCharactersInString:@\n] retain];
     
        }
        return [self extractCharactersSeparatedByCharactersInString:sLineSeparatorCharacterSet];
    }
     
    -(NSMutableString *) extractCharactersSeparatedByCharactersInString:(NSCharacterSet *)extractSet {
        NSMutableString* foundCharacters = nil;
        while (foundCharacters.length<=0 && self.length>0) {
            NSRange r = [self rangeOfCharacterFromSet: extractSet ];
            if (r.location != NSNotFound) {
                // il y a une occurence du charSet - extraction puis suppression des caractères extraits
                foundCharacters = [[self substringToIndex:r.location] mutableCopy];
                [self deleteCharactersInRange: NSMakeRange(0, NSMaxRange(r))];
            } else {
                // pas d'ocurence de charSet - c'est le dernier paquet de caractères
                foundCharacters = [[self copy] autorelease];
                [self setString:@""];
            }
        }
        return foundCharacters;   
    }

     


    Merci encore pour votre aide...



  •  


     j'ai dû faire un retain sur mes deux statics, et je me demande quand je dois les libérer... Probablement à  la fin de l'application, 

     



     


    Pourquoi ? Tu penses qu'ils sont où tes statics une fois que ton appli a quittée  :lol:




  • Pourquoi ? Tu penses qu'ils sont où tes statics une fois que ton appli a quittée  :lol:




     


    ;D  T'as raison, j'étais pas claire quand j'ai écrit çà . En fait, Je ne me suis pas pas très bien exprimée. Ce qui me gênait, c'est d'avoir des données qui restent toute la vie de l'application, mais en fait, je n'ai pas le choix, car c'est ce qu'il me faut !

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