Comment faire une recherche avec un NSPredicate

Bonjour à  tous,


 


voilà  j'ai un petit problème : 


 


je fais une recherche avec 



NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@SELF contains[cd] %@",searchText];

sauf que dans ce cas la, ca fonctionne si j'ai seulement des strings dans mon arraylist. 


 


Maintenant, j'ai une arraylist qui contient que des contacts .:



[contactSearch addObject:monContact];

et je voudrais faire une recherche sur les noms . Sauf que quand je mets SELF.name , cela ne fonctionne pas . J'ai une exception . 



NSUnknownKeyException', reason: '[<Contact 0xa0b4db0> valueForUndefinedKey:

Voici ma classe Contact : 



@interface Contact : NSObject


@property NSString * name;

Que mettre dans ma condition de mon predicate? Qu'est ce que j'ai oublié ?


Réponses

  • Bonjour,


     


    bizarre... car ceci fonctionne chez moi:



    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
    self.array = [[NSMutableArray alloc] init] ;

    [self.array addObject:[self objectWithName:@Colas]];
    [self.array addObject:[self objectWithName:@Ada]];
    [self.array addObject:[self objectWithName:@Jojo]];
    [self.array addObject:[self objectWithName:@Colas bis]];

    NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@name contains[cd] %@",@Colas];

    NSArray * newArray = [self.array filteredArrayUsingPredicate:resultPredicate] ;

    NSLog(@%@", newArray) ;
    }


    - (MyObject *)objectWithName:(NSString *)name
    {
    MyObject * result ;

    result = [[MyObject alloc] init] ;

    result.name=name ;

    return result ;
    }
  • mirail67mirail67 Membre
    avril 2014 modifié #3

    Lorsque j'ajoute 



    [contactSearch addObject:[monContact get_Name]];

    à  la place de 



    [contaSearch addObject:monContact];

    cela marche parfaitement avec 



     [NSPredicate predicateWithFormat:@SELF contains[cd] %@",searchText];

    . Dois-je ajouter une propriété ou quoi que ce soit dans ma classe Contact ? Je suis un peu perdu. De plus, c'est un mutablearray que j'ai et non un mutabledictionary


     


    Mais bug toujours avec name


  • colas_colas_ Membre
    avril 2014 modifié #4

    Plusieurs remarques avant de te répondre


     


    1) [monContact get_Name]];   ---> on dirait du Java !!! Si tu ne suis pas les règles de nommage de Objective-C, comment veux-tu utiliser les patterns d'Apple ? Quand tu fais [NSPredicate predicateWithFormat:@name contains[cd] %@",@Colas]; tout est basé sur le fait qu'il y a une méthode -(NSString*)name dans ta classe.


     


    Ta méthode get_Name devrait s'appeler -(NSString*)name


     


    2) Quand tu utilises une @property NSString*, il est conseillé de mettre l'option copy :  @property(copy) NSString*


     


     


    Ton problème pourrait bien venir du 1)


  • Bonne remarque colas2 . Je viens de changer cela en name. C'est juste du test ^^. 


    Donc dans mon NSPredicate j'ai :



     [NSPredicate predicateWithFormat:@name contains[cd] %@",searchText];

    Mais ca plante toujours avec la meme erreur : '



    NSInvalidArgumentException', reason: '-[Contact copyWithZone:]: unrecognized selector sent to instance 0x8d7f480'

    Pourtant j'ai bien mis "name" partout, dans ma classe et dans le predicate ... j'ai mis (copy) aussi ... 


  • L'erreur indique qu'il essaye d'appliquer la méthode -(id)copy sur un object de type Contact.


     


    D'après mon expérience (OSX mais il se peut que ce soit pareil pour iOS), cela peut venir d'un problème sur un xib, où tu ferais référence à  un objet de type Contact.


     


    Astuce aussi dans ton cas, tu peux régler le debugguer pour qu'il t'amène en mode debug sur la ligne qui plante : cf. les images jointes


     


  • D'apres les breakpoint, c'est ma ligne  



    searchResults = [contactSearch filteredArrayUsingPredicate:resultPredicate];

    qui planterai . 


  • Alors tu peux essayer de cliquer sur ce bouton, cf. image


     


  • Avant de lancer ton filtre, fais un NSLog(@%@", contactSearch) ;


  • Mon nslog : 


     



    "<Contact: 0x8c8b0d0>",
        "<Contact: 0x8c8cd80>",
        "<Contact: 0x8cdbe60>",
        "<Contact: 0x8cd9b60>",
        "<Contact: 0x8ccba70>",
        "<Contact: 0x8cd4320>",
        "<Contact: 0x8ccda80>",
        "<Contact: 0x8ccfd20>",
        "<Contact: 0x8c9b3a0>",
        "<Contact: 0x8cdac20>",
        "<Contact: 0x8cdaa20>",
        "<Contact: 0x8cdad10>",
        "<Contact: 0x8cccfb0>",
        "<Contact: 0x8ccb270>",
        "<Contact: 0x8cd8430>",
        "<Contact: 0x8cc9e10>",
        "<Contact: 0x8cd2860>",
        "<Contact: 0x8cdb050>",
        "<Contact: 0x8cd1460>",
        "<Contact: 0x8cccab0>",
        "<Contact: 0x8cda930>",
        "<Contact: 0x8cda840>",
        "<Contact: 0x8cd78e0>",
        "<Contact: 0x8cd8b70>",
        "<Contact: 0x8cdaf30>",
        "<Contact: 0x8cd5270>",
        "<Contact: 0x8cd85a0>",
        "<Contact: 0x8cd8f80>",
        "<Contact: 0x8cd2090>",
        "<Contact: 0x8cd0960>",
        "<Contact: 0x8cca300>",
        "<Contact: 0x8cdbeb0>",
        "<Contact: 0x8cd8870>",
        "<Contact: 0x8c90aa0>",
        "<Contact: 0x8ccd090>",
        "<Contact: 0x8cd4730>",
        "<Contact: 0x8c88be0>",
        "<Contact: 0x8c8c880>",
        "<Contact: 0x8c91100>",
        "<Contact: 0x8cdbce0>",
        "<Contact: 0x8cdb140>"
  • Et si tu fais NSLog(@%@", [contactSearch valueForKey:@name]) ; ?


  • lorsque je met cela j'ai 



    this class is not key value coding-compliant for the key name.'

    pourtant j'ai bien ma méthode name 

  • Le problème ne vient donc pas de NSPredicate, mais de la @property qui est mal synthétisée.


     


    Pour déclarer une @property (une @property est un couple de méthodes, associée à  un nom, une méthode pour le getter et une méthode pour le setter) Il faut juste mettre dans ton .h



    @property (nonatomic, readwrite, copy) NSString* name ;

    Cela va automatiquement créer deux méthodes (elles ne sont pas écrites et tu ne les vois pas parce qu'elles sont créées lors de la compilation), -(NSString*)name et -(void)setName:(NSString*)aName.


     


    Au passage, c'est d'ailleurs ces méthodes qui sont appelées lors que tu utilises la notation pointée :



    NSLog(@%@", self.name) // affiche le name
    self.name = @Colas // ça sette le name

    Et (si tu as une version suffisamment récente de xcode) : tu n'as rien à  mettre dans le .m


    Tu n'as pas non plus à  déclarer de variable name.


  • J'ai mis la propriété et cela fonctionne toujours pas. A mon avis, je ne comprends pas bien le concept. Donc , en fait mon but étant de faire une recherche sur mes contacts, et avec ce résultat, cliquer sur une contact et qui m'ouvre une autre vue avec les différents détails du contact(telephone,mobile etc... ).


    Donc dans ma méthode



     - (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope 

    j'ai



     NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@SELF contains[cd] %@",searchText];

    . Elle fonctionne très bien lorsque mon arrayslist contient seulement des nsstring. Maintenant, lorsque je fais  



    [contactSearch addObject:monContact]

     ça plante. j'ai bien mis dans .h de ma classe Contact la propriété. Aucun code n'a été généré . Est-ce bien dans la classe Contact que je dois mettre cela, et non dans ma viewcontroller.h ? Je pense que j'oublie une étape importante ... 


  • ça plante où exactement ?


     


     


    à  [contactSearch addObject:monContact] ?


     


    ou ailleurs ? Quel est le message d'erreur ?


     


    Si tu joins ton projet, je pourrai te dire où est l'erreur.


  • Je te remercie colas2 , mais je viens juste de résoudre mon problème. Je te remercie pour ton aide précieuse . Voici mon code : 



    - (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
    {
        NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@name contains[c] %@",searchText];
        NSMutableArray *aa = [[NSMutableArray alloc]init];;
     
            searchResults = [conta filteredArrayUsingPredicate:resultPredicate];
            
      
    }

    Enfait, tout fonctionnait parfaitement, mais lors de mon affichage dans ma tableview , je faisais : 



     



    if (tableView == self.searchDisplayController.searchResultsTableView) {
            cell.nameLabel.text = [searchResults objectAtIndex:indexPath.row];

    au lieu de :  



    if (tableView == self.searchDisplayController.searchResultsTableView) {
            cell.nameLabel.text = [[searchResults objectAtIndex:indexPath.row] get_Name];

     

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