J'utilise Core Data et je veux seulement récupérer le premier enregistrement de mon jeu de données, est-ce possible?
Vous pouvez utiliser la méthode setFetchLimit:
sur NSFetchRequest pour limiter le nombre d'enregistrements extraits. Donc, 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 devez 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: / En fonction de votre type de magasin, limiter le nombre de lectures peut entraîner des gains de performances spectaculaires. Si ce n'est pas le cas, ou si vous n'êtes pas inquiet pour les performances et que vous utiliserez peut-être 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 firstObject];
Si vous êtes sûr que le tableau contient un objet, vous pouvez même l'obtenir 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". Vous devrez peut-être non seulement définir la limite d'extraction sur 1, mais également trier les résultats dans l'extraction.
Par exemple, j'ai un groupe d'objets User
dans ma base de données et je souhaite trouver le premier qui a créé un compte. (En supposant que j'ai déjà le modèle pour User
, y compris 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
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = entity;
request.sortDescriptors = @[ sortDescriptor ];
request.fetchLimit = 1;
NSError *error;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
User *result = fetchResults.firstObject; // nil on failure; check value of 'error'
Si vous ne triez pas les résultats avant de limiter l'extraction, rien ne permet de savoir quels résultats seront renvoyés "en premier".
J'ai utilisé les catégories Objective-C pour ajouter une méthode de classe NSManagedObject
appelée firstInManagedObjectContext:
.
// 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
Ajoutez ces fichiers à votre projet et veillez à les lier à votre cible. Ensuite, #import "NSManagedObject+Additions.h"
dans les fichiers .m
où vous utilisez la méthode de classe firstInManagedObjectContext:
.
Appelez-le depuis n'importe quelle sous-classe concrète (et non abstraite) de NSManagedObjectContext
. Il suffit de lui transmettre le NSManagedObjectContext *context
à partir duquel extraire l’objet géré. La méthode détecte le (NSString *)entityName
à partir du nom de la classe à laquelle elle est appelée. Rappelez-vous simplement de lancer le résultat pour une construction propre (sans avertissements).
J'utilise ceci pour une classe d'objets gérés dont je sais que je ne dispose que d'une instance sauvegardée. Si vous avez plusieurs instances sauvegardées, vous pouvez ajouter une 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 toutefois pas sûr si les ID d'objet sont ordonnés.
Imaginez que vous ayez un objet Event
qui descend de NSManagedObjectContext
. Vous pourriez faire:
Event *event = (Event *)[Event firstInManagedObjectContext:context];
Après avoir lu le Tutoriel iOS 4 Blocs de Pragmatic Studio , je me suis rendu compte que ce code pouvait être amélioré et rendu encore plus modulaire en ajoutant une autre fonction, appelez-le + fetch
et en ajoutant une NSFetchRequestBlock
(qui prendrait le fetchRequest
comme argument) & NSFetchRequestFailureBlock
comme arguments pour personnaliser la demande d'extraction et le traitement de l'erreur de demande d'extraction, respectivement. Je vous mets au défi de vous attaquer à cela! :)
Définissez simplement la propriété fetchLimit
de votre NSFetchRequest
sur 1, puis sélectionnez le premier élément des résultats NSArray
en utilisant la méthode firstObject
pour éviter toute erreur index out of bound for empty array
.
Voici l'exemple de code:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ENTITY_NAME" inManagedObjectContext:yourMoc];
NSPedicate *predicate = [NSPredicate predicateWithFormat:@"PREDICATE FORMAT"];
[request setEntity:entity];
[request setPredicate:predicate];
[request setFetchLimit:1];
NSError *error;
NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
NSManagedObject *object = [results firstObject];
if (object) {
// there is at least one object matching you predicate
} else {
// there is no object matching your predicate in the moc
}
C’est ma tentative. N.B. l'entité de livre 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);
Frappez cela dans une classe d'assistance 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;
}
}