comportement erratique d'un NSNumberFormatter sur un NSSearchField

iApasDeMaliApasDeMal Membre
août 2013 modifié dans API AppKit #1

Bonjour à  tous,


 


j'ai un NSSearchField pour déclencher une action à  chaque saisie de texte :



IBOutlet NSSearchField * numericSearchField;

je lui applique un formateur comme ça :



NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numericSearchField setFormatter:formatter];
[formatter release];
formatter = nil;

Mais le formatage ne se fait pas du tout correctement, il efface l'ensemble de la saisie de texte quand j'insère un caractère non numérique et d'autres comportements étranges.


 


À quoi c'est dû?


 


merci d'avance pour vos idées


Réponses

  • Le NSSearchField dispose de facilité pour faire des recherche texte (en fait c'est plutôt le NSSearchFieldCell qui en dispose).


    Faire des recherches avec un NSNumber doit vraisemblablement nécessiter pas mal de customisation.


  • Merci de répondre si vite.


     


    Donc à  ton avis je n'utilise pas le bon contrôle pour formater - mettre en forme et corriger - à  la volée les saisies de textes de l'utilisateur?


     


    J'ai fait un essai avec un NSTextField qui reçoit des actions à  chaque frappe du clavier grâce à  :



    - (void)controlTextDidChange:(NSNotification*)notification;

    J'ai des problèmes similaires.


    Devrais-je en conclure que les NSNumberFormatter ne permettent pas de formater du texte à  la volée?


  • Bonjour,


     


    Je passais par là  et j'en profite pour poser une question. Je travaille avec ARC, c'est donc une pure question de curiosité. Les lignes de iApasDeMal :



    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    [formatter setNumberStyle:NSNumberFormatterDecimalStyle];
    [numericSearchField setFormatter:formatter];
    [formatter release];
    formatter = nil;

    font quoi une fois compilées? Pour l'ancien programmeur Pascal que je suis, cela équivaut à  faire



    [numericSearchField setFormatter: nil];

    mais en Objective-C je suppose que c'est différent. Est-ce que le setFormatter utilise une copie du NSFormatter, laissant l'original suspendu dans le vide? Est-ce que cet original est détruit lorsque le programme quitte la méthode? Est-ce que le release ne remet pas l'adresse à  nil?


    Merci de m'éclairer si vous avez du temps, ce n'est pas prioritaire.


  • AliGatorAliGator Membre, Modérateur

    Est-ce que le setFormatter utilise une copie du NSFormatter, laissant l'original suspendu dans le vide? Est-ce que cet original est détruit lorsque le programme quitte la méthode? Est-ce que le release ne remet pas l'adresse à  nil?

    o_O Heu tu veux dire que tu n'as jamais entendu parlé du Reference Counting qu'utilise Cocoa, des retain/release, des propriétés qui sont strong ou weak ou assign ou retain ou copy pour justement indiquer ces différences ?

    Si tu n'es pas au point sur ces concepts, c'est très urgent pour toi de te documenter dessus, car c'est quand même une des bases structurantes de la gestion mémoire. Et ARC ne change pas grand chose au problème d'ailleurs : certes avec ARC tu n'as pas à  appeler retain ou release c'est lui qui se charge de libérer la mémoire au besoin. Mais ça n'enlève pas que les concepts de "strong references" ou "weak references" sont un concept important à  connaà®tre. Car même avec ARC, si tu mets une weak reference au lieu d'une strong reference qqpart, y'a des choses qui vont mal se passer...


  • o_O Heu tu veux dire que tu n'as jamais entendu parlé du Reference Counting qu'utilise Cocoa, des retain/release, des propriétés qui sont strong ou weak ou assign ou retain ou copy pour justement indiquer ces différences ?




    Si, justement, c'est pour ça que je ne comprends pas le code de iApasDeMal...

  • AliGatorAliGator Membre, Modérateur
    Bah pourtant il me parait très clair, sachant que d'après la doc les setters de NSObject comme `setFormatter:` sont strong par convention, ce qui est cohérent avec les concepts d'ownership de base de Cocoa (à  savoir "celui qui crée un objet est en charge de sa gestion mémoire")...
    Autrement dit, c'est bien à  toi de releaser le formatter car c'est toi qui l'a alloc/init, donc c'est de ta responsabilité d'équilibrer tout alloc ou retain ou copy par un release ou autorelease. Après, c'est `setFormatter` qui se préoccupe de faire un `retain` de son côté du formatter qu'on lui passe, s'il a besoin d'en garder une référence (ce qui est le cas s'il ne veut pas risquer que le formatter soit détruit entre temps).

    De toute façon si `setFormatter:` ne faisait pas le `retain` en interne, alors tu aurais un crash assuré (et non l'équivalent d'avoir fait un `setFormatter:nil` comme tu semblais le penser dans ton message plus haut). Ou alors faudrait pas faire le `release` de ton côté pour pas que ça crash (et ça serait toujours pas équivalent à  `setFormatter:nil` de toute façon) mais ça violerait la règle de base de Cocoa sur la "ownership responsability".

    Si `setFormatter:` retenait une `weak reference` mais qu'on tournais sous iOS4, ou si c'était une `unsafe_unretained reference` sous iOS4 ou suppérieur, alors tu aurais un crash. Si tu avais une `weak reference`sous iOS5 ou supérieur, et donc que le mécanisme de "Zeroing Weak Reference" (ZWR) était actif (mécanisme qui fait que les références vers les objets qui sont depuis détruits se remettent à  nil automatiquement), tu aurais un formatter remis à  nil car tu l'aurais détruit depuis. Tout cela n'aurais pas trop de sens à  l'usage et ne respecterais pas les conventions de Cocoa quant aux setters sur des NSObject et aux principes d'objets owners (composition). Mais heureusement et évidemment, `setFormatter:` maintiens une `strong reference` sur le formatter, ce qui parait logique vu les conventions Cocoa et le fonctionnement naturel attendu.


    Si tout cela n'est pas clair ni naturel pour toi, c'est qu'il te faut réviser ce qu'il y a sous la notion de `strong reference` ;) En particulier le fait que chacun est responsable des objets qu'il crée (ownership responsability) " concept qui a moins besoin d'être connu avec ARC car ARC gère ça pour nous " et surtout les concepts de strong/weak references (qui est vrai avec ou sans ARC, lui) qui sont primordiales pour éviter les retain cycles.
  • Après cette importante mise au point,


    Existe-t-il un moyen d'utiliser un NSNumberFormatter pour formater un champ de saisi à  la volée, c'est à  dire après chaque entrée au clavier?


    Sinon cela voudrait dire qu'il faudrait que je revienne à  ce bout de code



    - (NSString*)correctDecimalString:(NSString*)string{
    NSCharacterSet * charSet = [NSCharacterSet characterSetWithCharactersInString:@0123456789];
    NSText * fieldEditor = [[fxView window] fieldEditor:NO forObject:nil];
    NSRange selectedRange = [fieldEditor selectedRange];

    char * stringResult = malloc([string length]);
    int cpt=0;
    for (int i = 0; i < [string length]; i++) {
    unichar c = [string characterAtIndex:i];
    if ([charSet characterIsMember:c]) {
    stringResult[cpt]=c;
    cpt++;
    }else{
    NSBeep();
    if(selectedRange.location != 0) selectedRange.location --;
    [fieldEditor setSelectedRange:selectedRange];
    [[NSNotificationCenter defaultCenter] postNotificationName:@FXSearchBoxDecimalError object:fxView];
    }
    }
    stringResult[cpt]='\0';
    NSString * decimalString = [NSString stringWithUTF8String:stringResult];
    free(stringResult);
    return decimalString;
    }
  • Bout de code qui ne permet pas toutes les subtilités que possède un NSNumberFormatter


  • AliGatorAliGator Membre, Modérateur
    août 2013 modifié #10
    Tu as essayé avec ça ?
    [numberFormatter setPartialStringValidationEnabled:YES]
  • Non, je teste ça tout de suite, merci du tuyau.


  • AliGatorAliGator Membre, Modérateur
    Après j'en sais rien hein, je viens juste de le découvrir dans la doc (que je pensais que tu avais lue...) ;)
  • iApasDeMaliApasDeMal Membre
    août 2013 modifié #13

    Je viens de tester, j'ai des erreurs bizarres que ce soit sur un NSTextField ou un NSSearchField : quand j'entre plus de 4 chiffres, l'affichage revient à  zéro, plus de chiffre, et quand j'entre autre chose qu'un chiffre, tout l'affichage s'efface.


    Peut-être que ce sont les symptômes d'une erreur ou d'une mauvaise manipulation qui te dit quelque chose.


     


    Je vais continuer de regarder.


  • AliGatorAliGator Membre, Modérateur
    Tu as regardé la documentation sur les NSNumberFormatter, sa classe parent NSFormatter, et le "Data Formatting Guide" mentionné en haut de ces 2 docs, pour voir les infos qu'ils te donnent ?

    Parce que bon j'ai pas utilisé de NS*Formatter depuis une paye donc je ne saurai pas t'aider en direct, mais l'info est forcément dans la doc, et de toute façon ça ne fait jamais de mal de lire les Programming Guides qui regorgent d'infos intéressantes voire primordiales ;)
  • Je les ai regardé en diagonal et donc sans doute trop vite, je vais m'y replonger


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