J'utilise Core Data et je veux seulement récupérer le premier enregistrement de mon jeu de données, est-ce possible ?
Réponses
Trop de publicités?Vous pouvez utiliser le setFetchLimit:
sur NSFetchRequest pour limiter le nombre d'enregistrements récupérés. Ainsi, si vous ne voulez que le premier enregistrement :
// Given some existing NSFetchRequest *request and NSManagedObjectContext *context:
[request setFetchLimit:1];
NSError *error;
NSArray *results = [context executeFetchRequest:request error:&error];
Notez que l'appel à executeFetchRequest:error:
retournera toujours un NSArray ; vous devrez toujours extraire le premier objet du tableau avant de pouvoir l'utiliser, même s'il s'agit d'un tableau de taille 1.
Une autre méthode, moins efficace : Selon le type de magasin, la limitation de l'extraction peut accélérer considérablement les performances. Cependant, si ce n'est pas le cas, ou si vous n'êtes pas si préoccupé par les performances, et que vous pourriez utiliser plus de données plus tard, vous pouvez simplement extraire le premier objet du tableau à l'avance :
// Given some existing result NSArray *results:
NSManagedObject *firstManagedObject = [results objectAtIndex:0];
Vous pouvez même le placer dans un autre tableau (pour l'utiliser dans un UITableViewController, par exemple) en procédant comme suit :
// Again, with some NSArray *results:
NSArray *singleObjectResult = [results subarrayWithRange:NSMakeRange(0, 1)];
Bien sûr, cela dépend en partie de ce que vous entendez par "premier enregistrement". Il se peut que vous deviez non seulement fixer la limite de la recherche à 1, mais aussi trier les résultats de la recherche.
Par exemple, j'ai un tas de User
dans ma base de données, et je veux trouver le premier qui a créé un compte. (En supposant que j'ai déjà le modèle de User
dont un attribut nommé accountCreatedDate
.)
NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"accountCreatedDate" ascending:YES]; // ascending YES = start with earliest date
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
NSError *error;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setSortDescriptors:sortDescriptors];
[request setFetchLimit:1];
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
User *result = nil;
if ([fetchResults count]>0)
result = [fetchResults objectAtIndex:0];
[request release];
[sortDescriptors release];
[sortDescriptor release];
Si vous ne triez pas les résultats avant de limiter la recherche, il est impossible de savoir quels résultats seront renvoyés "en premier".
J'ai utilisé les catégories Objective-C pour ajouter un NSManagedObject
méthode de classe appelée firstInManagedObjectContext:
.
Code source
// NSManagedObject+Additions.h
@interface NSManagedObject (Acani)
+ (NSString *)entityName;
+ (NSEntityDescription *)entityInManagedObjectContext:(NSManagedObjectContext *)context;
+ (NSManagedObject *)firstInManagedObjectContext:(NSManagedObjectContext *)context;
@end
// NSManagedObject+Additions.m
#import "NSManagedObject+Additions.h"
@implementation NSManagedObject (Acani)
+ (NSString *)entityName {
return NSStringFromClass([self class]);
}
+ (NSEntityDescription *)entityInManagedObjectContext:(NSManagedObjectContext *)context {
return [NSEntityDescription entityForName:self.entityName inManagedObjectContext:context];
}
+ (NSManagedObject *)firstInManagedObjectContext:(NSManagedObjectContext *)context {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[self entityInManagedObjectContext:context]];
[fetchRequest setFetchLimit:1];
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
if (fetchedObjects == nil) {
NSLog(@"Fetch sender error %@, %@", error, [error userInfo]);
return nil;
} else if ([fetchedObjects count] > 0) {
return [fetchedObjects objectAtIndex:0];
}
return nil;
}
@end
Utilisation
Ajoutez ces fichiers à votre projet et assurez-vous de les lier à votre cible. Ensuite, #import "NSManagedObject+Additions.h"
dans le .m
où vous utilisez l'option firstInManagedObjectContext:
méthode de classe.
Appelez-le à partir de n'importe quelle sous-classe concrète (non abstraite) de NSManagedObjectContext
. Il suffit de lui passer le NSManagedObjectContext *context
à partir duquel il faut récupérer l'objet géré. La méthode détecte le (NSString *)entityName
du nom de la classe sur laquelle il est appelé. N'oubliez pas de caster le résultat pour une construction propre (sans avertissements).
Je l'utilise pour une classe d'objets gérés dont je sais que je n'ai qu'une seule instance enregistrée. Si vous avez plus d'une instance sauvegardée, vous pouvez ajouter un fichier NSSortDescriptor
comme le suggère @Craig McMahon. Vous pouvez également essayer de trier par objectID
au lieu de accountCreatedDate
si tous les objets sont créés sur le même périphérique. Je ne suis pas sûr, cependant, que les ID des objets soient ordonnés.
Exemple
Imaginez que vous ayez un Event
qui descend de NSManagedObjectContext
. Vous pourriez le faire :
Event *event = (Event *)[Event firstInManagedObjectContext:context];
Blocs
Après avoir lu le Tutoriel sur les blocs iOS 4 de Pragmatic Studio j'ai réalisé que ce code pouvait être amélioré et rendu encore plus modulaire en ajoutant une autre fonction, appelée + fetch
et l'ajout d'un NSFetchRequestBlock
(qui prendrait le fetchRequest
comme argument) & NSFetchRequestFailureBlock
comme arguments pour personnaliser la demande de récupération et le traitement de l'erreur de demande de récupération, respectivement. Je vous mets au défi de vous attaquer à cela ! :)
C'est ma tentative. N.B. L'entité Book hérite de NSManagedObject.
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"isbn ==9780786660506"];
Book *book = (Book*) [CoreDataHelper getEntityFromFetchedResultsController:@"Book" :predicate :nil :YES :application.managedObjectContext];
if (book !=nil) NSLog(@"book entity %@",book.title);
Bang ceci dans une classe d'aide statique appelée CoreDataHelper
+ (NSManagedObject*)getEntityFromFetchedResultsController: (NSString*) entityName : (NSPredicate *) predicate : (NSString*) sortKey : (BOOL) sortAscending : (NSManagedObjectContext *) managedObjectContext
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
[request setFetchLimit:1];
// If a predicate was passed, pass it to the query
if(predicate != nil)
{
[request setPredicate:predicate];
}
// If a sort key was passed, use it for sorting.
if(sortKey != nil)
{
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
}
NSError *error;
NSMutableArray *mutableFetchResults = [[[managedObjectContext executeFetchRequest:request error:&error] mutableCopy] autorelease];
if (error !=nil){
NSLog(@"error %@", error);
}
if ([mutableFetchResults count] >0)
{
NSManagedObject *firstObject = [mutableFetchResults objectAtIndex:0];
return firstObject;
}else
{
return nil;
}
}