2010-05-19 4 views
1

Utilisation de données de base avec un magasin sqlite sur iPhone .... J'ai un tas d'entités d'image de bande dessinée, chacune avec une chaîne qui comprend la question de bande dessinée de #, par exemple: image.imageTitle = @"Issue 12: Special Edition";Limites de mots ( b) dans NSPredicate provoquant NSFetchRequest pour retourner aucun objet géré

une partie de l'interface utilisateur permet à l'utilisateur de saisir un numéro d'émission pour passer à la question suivante. Mon code initial pour cela était sloooooooow parce que imageAtIndex: interroge les données de base pour un objet à la fois. Sur plusieurs centaines de numéros, cela peut prendre jusqu'à 40 secondes pour passer la première boucle!

code lent:

// Seek forward from the next page to the right 
for (i = currentPage + 1; i < [self numberOfPages]; i++) { 
    iterationString = [[self imageAtIndex:i] imageTitle]; 
    iterationNumber = [[iterationString stringByTrimmingCharactersInSet:nonDigits] intValue]; 

    if (issueNumber == iterationNumber) { 
    keepLooking = NO; 
    break; 
    } 
} 
// If nothing was found to the right, seek forward from 0 to the current page 
if (i == [self numberOfPages] && keepLooking) { 
    for (i = 0 ; i < currentPage; i++) { 
    iterationString = [[self imageAtIndex:i] imageTitle]; 
    iterationNumber = [[iterationString stringByTrimmingCharactersInSet:nonDigits] intValue]; 

    if (issueNumber == iterationNumber) { 
    keepLooking = NO; 
    break; 
    } 
    } 
} 

Espérant une solution beaucoup plus efficace, j'ai décidé d'essayer de faire une requête directe sur les données de base comme ceci:

NSString *issueNumber = @"12"; 
    NSString *issueWithWordBoundaries = [NSString stringWithFormat:@"\\b%@\\b",issueNumber]; 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(groupID == %@) AND (imageTitle CONTAINS %@)", groupID, issueWithWordBoundaries]; 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"CBImage" inManagedObjectContext:self.managedObjectContext]; 
[fetchRequest setEntity:entity]; 

[fetchRequest setPredicate:predicate]; 
[fetchRequest setIncludesSubentities:NO]; // Not sure if this is needed, but just in case.... 

// Execute the fetch 
NSError *error = nil; 
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error]; 

    // [fetchedImages count] == 0 

Entre le Predicate Programming Guide et la ICU regex specs, j'ai pensé que les \ b's aiderait à empêcher la recherche de 12 retournant 120, 121, 122, etc. Au lieu de cela, il ne retourne rien du magasin du tout!

D'autre part, si je laisse hors les limites de mots et rechercher plutôt pour stringWithFormat:@"%@",issueNumber, je reçois des dizaines d'objets gérés sont revenus, de 12 à 129 à 412.

Ma meilleure estimation à ce stade est que je J'ai rencontré l'un des Constraints and Limitations de Core Data. Sinon, qu'est-ce que je fais de mal? Si oui, existe-t-il une solution qui offre à la fois une correspondance exacte et la vitesse d'un seul fetch?

Répondre

1

Il s'avère que les limites de mots étaient un reflet rouge: Mon problème était une variante sur this issue: La regex ne pouvait pas réussir sans certaines jokers pour correspondre aux bits dont je ne me souciais pas dans les imageTitles.

La solution de cas général pour trouver une expression exacte à l'aide NSPredicate est donc:

NSString *exactPhrase = @"phrase_you_hope_to_find_in_another_string"; 
NSString *regularExpression = [NSString stringWithFormat:@".*\\b%@\\b.*",exactPhrase]; 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"stringToSearch CONTAINS %@", exactPhrase]; 
// Assuming a string or an entity's string attribute named stringToSearch 
+0

Corrigez-moi si je me trompe mais il semblerait que vous n'utilisiez pas réellement 'regularExpression', au lieu de faire une recherche CONTAINS en utilisant votre phrase de recherche originale. – taber

+0

Euh, ça ressemble à ça, @taber. Pour dire la vérité, ça fait assez longtemps que je n'ai aucun souvenir du projet, ou quel est le problème. Cette question a eu très peu d'activité en 4 ans, donc je pense que je vais juste l'indiquer pour la suppression. :-) – clozach

+0

Je le laisserais en place, je l'ai trouvé en cherchant à utiliser une correspondance de prédicat avec les limites de mots et ça m'a aidé !! Vous avez juste à faire: '" stringToSearch CONTAINS% @ ", regularExpression' mais j'ai aussi dû d'abord échapper des caractères spéciaux dans' exactPhrase'. – taber

3

\b fait référence à un caractère de retour arrière. Essayez

[NSString stringWithFormat:@"\\b%@\\b",issueNumber]; 
//       ^^ ^^ 

Et pour effectuer une correspondance RegEx, utilisez MATCHES, pas CONTAINS.

+0

Grande pêche, mais malheureusement, c'était juste une faute de frappe de ma part causée par avoir essayé tant de variantes sur l'expression. Echapper au \ 's donne toujours les mêmes résultats: nada! J'ai maintenant mis à jour ma question de @ "\ b% @ \ b" à @ "\\ b% @ \\ b" maintenant. Merci, Kenny! – clozach

+0

@clozach: Voir mise à jour. – kennytm