Je travaille sur une application iPhone qui obtient un certain nombre d'objets d'une base de données. J'aimerais stocker ces utilisateurs à l'aide de données de base, mais j'ai des problèmes de relations avec mes relations.
Un détail contient un nombre de POI (points d'intérêt). Lorsque j'approche un ensemble de POI à partir du serveur, ils contiennent un identifiant de détail. Afin d'associer le POI avec le détail (par ID), mon processus est le suivant: Requête le managementObjectContext pour le détaillant. Si ce détail existe, ajoutez-y le POI. Si ce n'est pas le cas, créez le détail (il a d'autres propriétés qui seront peuplées paresseusement). P>
Le problème avec cela est la performance. La performance des requêtes constantes des données de base est lente, au point où l'ajout d'une liste de 150 POI prend une minute grâce aux multiples relations impliquées. P>
dans mon ancien modèle, avant les données de base (divers objets de cache Nsdiction) Ce processus était super rapide (recherchez une clé dans un dictionnaire, puis la créez si cela n'existe pas) P>
J'ai plus de relations que celle-ci, mais à peu près tout le monde doit faire ce chèque (Certains sont nombreux à beaucoup, et ils ont un vrai problème). P>
Quelqu'un a-t-il des suggestions pour comment je peux l'aider? Je pourrais effectuer moins de questions (en recherchant un certain nombre d'identifiants différents), mais je ne suis pas sûr de combien cela aidera. P>
Certains code: P>
POI *poi = [NSEntityDescription insertNewObjectForEntityForName:@"POI" inManagedObjectContext:[(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext]]; poi.POIid = [attributeDict objectForKey:kAttributeID]; poi.detailId = [attributeDict objectForKey:kAttributeDetailID]; Detail *detail = [self findDetailForID:poi.POIid]; if(detail == nil) { detail = [NSEntityDescription insertNewObjectForEntityForName:@"Detail" inManagedObjectContext:[(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext]]; detail.title = poi.POIid; detail.subtitle = @""; detail.detailType = [attributeDict objectForKey:kAttributeType]; } -(Detail*)findDetailForID:(NSString*)detailID { NSManagedObjectContext *moc = [[UIApplication sharedApplication].delegate managedObjectContext]; NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Detail" inManagedObjectContext:moc]; NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; [request setEntity:entityDescription]; NSPredicate *predicate = [NSPredicate predicateWithFormat: @"detailid == %@", detailID]; [request setPredicate:predicate]; NSLog(@"%@", [predicate description]); NSError *error; NSArray *array = [moc executeFetchRequest:request error:&error]; if (array == nil || [array count] != 1) { // Deal with error... return nil; } return [array objectAtIndex:0]; }
3 Réponses :
Cette page fournit une aide sur l'optimisation des performances: http: //developer.apple.com/documentation/cocoa/conceptual/coredata/articles/cdperformance.html#//apple_ref/doc/uid/tp40003468-sw1 P>
Bien que pas très efficace, pourquoi ne pas simplement les construire en mémoire avec un nsdiction? Lisez tout à partir des données de base dans une NSDictionary, puis fusionnez dans vos données, en remplaçant tout dans les données de base. P>
Idée intéressante. Le motif serait alors, chaque fois que la création d'objets 1. récupérez la plage possible d'objets associés, stockez dans NSDictionary avec la clé 2. Si l'ID existe, ajoutez la relation à cet objet 3. Si l'ID ne l'a ajouté pas, ajoutez le nouvel objet. au dictionnaire et aux données de base. Ajouter la relation.
J'ai tout ce que ça va travailler vraiment bien, grâce à Norman, qui m'a mis sur le bon chemin. Je posterai ma classe d'assistance ici pour d'autres personnes.
Fondamentalement, ma classe d'assistance recherchera si une NSManèdeObject existe pour certains identifiants et peut le créer pour une pièce d'identité. Cela s'exécute assez rapidement pour moi, avec 1 000 opérations de recherche / création de 1 000 opérations prenant environ 2 secondes sur mon iPhone (j'ai aussi fait quelques autres choses là-bas, de la recherche / création pure est probablement plus rapide). P>
Il le fait Mise en cache un dictionnaire de tous les NsmanagedObjects et vérifiant cette cache plutôt que d'exécuter un nouveau Nsfetchrequest. P>
Quelques modifications pouvant aider les choses à accélérer encore plus loin: 1. Obtenez uniquement les propriétés sélectionnées pour les NsmanagedObjects 2. Obtenez uniquement la propriété Identifiant pour le NSManageDObject dans un dictionnaire, au lieu de tout l'objet. Dans mes tests de performance, la requête unique n'était pas la partie lente (mais avec seulement 1 000 articles, je m'attendais à ce qu'elle soit rapide). La partie lente était la création des articles. P>
#import "CoreDataUniquer.h" @implementation CoreDataUniquer //the identifying property is the field on the NSManagedObject that will be used to look up our custom identifier -(id)initWithEntityName:(NSString*)newEntityName andIdentifyingProperty:(NSString*)newIdProp { self = [super init]; if (self != nil) { entityName = [newEntityName retain]; identifyingProperty = [newIdProp retain]; } return self; } -(NSManagedObject*)findObjectForID:(NSString*)identifier { if(identifier == nil) { return nil; } if(!objectList) { NSManagedObjectContext *moc = [(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext]; NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entityName inManagedObjectContext:moc]; NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; [request setEntity:entityDescription]; NSError *error; NSArray *array = [moc executeFetchRequest:request error:&error]; objectList = [[NSMutableDictionary dictionary] retain]; for (NSManagedObject* p in array) { NSString* itemId = [p valueForKey:identifyingProperty]; [objectList setObject:p forKey:itemId]; } } NSManagedObject* returnedObject = [objectList objectForKey:identifier]; return returnedObject; } -(NSManagedObject*)createObjectForID:(NSString*)identifier { NSManagedObject* returnedObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:[(AppDelegate*)[UIApplication sharedApplication].delegate managedObjectContext]]; [returnedObject setValue:identifier forKey:identifyingProperty]; [objectList setObject:returnedObject forKey:identifier]; return returnedObject; } - (void) dealloc { DESTROY(entityName); DESTROY(identifyingProperty); [super dealloc]; } @end
Assurez-vous également que vous cochez l'option «Index» sur votre propriété Identifier.
Merci! Pouvez-vous s'il vous plaît aussi poster le fichier .h?
Vous essayez de trouver une entité avec la valeur d'attribut en cochant toutes les entités de Store. Vous accédez à tous ces actifs et cela change d'état de défaut sur une requête réelle. Je pense que vous devez utiliser le prédicat et la limitation pour Nsfetchrequest et exécuter la requête. Si comptez> 0, cela signifie que l'entité avec attribut existe déjà dans un magasin persistant. Après cela, vous pouvez accéder à ce résultat de la demande pour mettre à jour votre entité.
Consultez la section intitulée "Défautage par lots" sur la page intitulée "Performances de données de base" dans le Guide de programmation de données de base Xcode EM> que Norman lié à sa réponse.
n'atteignant que ces managrés dont Les identifiants sont dans code> une collection (
nsset code>,
nsarray code>,
nsdicdiction code>) des ID des objets renvoyés par le serveur peuvent Soyez encore plus efficace. P>
NSSet *oids = [[NSSet alloc] initWithObjects:@"oid1", @"oid2", ..., nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"oid IN %@", oids];
[oids release];
Expliquez vos objets plus en détail et publiez une partie du code que vous utilisez. C'est presque 100% probablement il y a un moyen de faire ce que vous faites déjà beaucoup plus vite.