2012-06-06 6 views
1

Je veux récupérer environ 200 NSManagedObject, la taille de chacun est d'environ 5 Mo. Si j'utilise executeFetchRequest, je reçois des avertissements de mémoire et des plantages d'applications (parce que récupéré NSManagedObjects apparaît dans la RAM de l'iPhone). Si je peux utiliser executeFetchRequest, je peux utiliser sortdescriptor pour trier les données par identifiant. Mais je ne peux pas (ou peut-être que je devrais définir les propriétés appropriées à NSFetchRequest, mais je ne sais pas, quelles propriétés). C'est pourquoi j'ai utilisé une autre approche pour charger une grande quantité de données: J'ai Entity Album, qui a de nombreuses entités SpecificImage. Et j'utiliser ce code pour récupérer toutes les images de l'album en cours:Données de base. Trier NSMutableSet de grande taille NSManagedObject

- (NSMutableSet *)getAllSpecificImages 
{ 
     NSString *entityName = kEntityName; 
     AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 
     NSManagedObjectContext *context = appDelegate.managedObjectContext; 
     NSEntityDescription *entityDesctiption = [NSEntityDescription 
                entityForName: entityName 
                inManagedObjectContext:context]; 
     // check if town exists 
     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id == %d", self.CurrentCategoryItemID]; 
     NSFetchRequest *requestToCheckExistense = [[NSFetchRequest alloc] init]; 
     [requestToCheckExistense setEntity:entityDesctiption]; 
     [requestToCheckExistense setPredicate:predicate]; 
     NSArray *objects = [context executeFetchRequest:requestToCheckExistense error:nil]; 
     [requestToCheckExistense release]; 
     if (objects == nil) 
     { 
      NSLog(@"there was an error"); 
      return nil; 
     } 
     NSManagedObject *object; 
     if ([objects count] > 0) 
     { 
      // edit item 
      object = [objects objectAtIndex:0]; 

     } 
     else 
     { 
      // if object doesn't exist, find max id to imlement autoincrement 
      NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
      [request setEntity:entityDesctiption]; 
      NSArray *allobjects = [context executeFetchRequest:request error:nil]; 
      [request release]; 
      NSInteger newID = 1; 
      if ([allobjects count] > 0) 
      { 
       NSNumber *maxID = [allobjects valueForKeyPath:@"@max.id"]; 
       newID = [maxID intValue] + 1; 
      } 

      // write item 
      object = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context]; 
      [object setValue:[NSNumber numberWithInt:newID] forKey:@"id"]; 
      self.CurrentCategoryItemID = newID; 
     } 

    NSMutableSet *set = [object mutableSetValueForKey:@"specificImages"]; 
    return set; 
} 

puis-je obtenir tableau de NSManagedObjects

NSMutableArray *array = [NSMutableArray arrayWithArray:[setOfManagedObjectsSpecificImages allObjects]]; 

mais j'essaie d'obtenir le tableau trié de cette NSManagedObjects et je reçois à nouveau avertissement de mémoire et les plantages de l'application. J'ai essayé d'utiliser

NSSortDescriptor *sortDiscriptor = [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:YES]; 
[array sortUsingDescriptors:[NSArray arrayWithObject:sortDiscriptor]]; 

et

[self quickSort:array left:0 right:([array count] - 1)]; 

- (void)quickSort: (NSMutableArray *)arr left:(NSInteger)left right:(NSInteger) right 
{ 
    @autoreleasepool { 
     int i = left, j = right; 

     int pivot = [((SpecificImage *)[arr objectAtIndex:(left + right)/2]).id intValue]; 



     /* partition */ 

     while (i <= j) { 
      while ([((SpecificImage *)[arr objectAtIndex:i]).id intValue] < pivot) 
      { 

       i++; 
      } 

      while ([((SpecificImage *)[arr objectAtIndex:j]).id intValue] > pivot) 
      { 

       j--; 
      } 

      if (i <= j) { 

       [arr exchangeObjectAtIndex:i withObjectAtIndex:j]; 

       i++; 

       j--; 

      } 

     }; 


     /* recursion */ 

     if (left < j) 
     { 
      [self quickSort:arr left:left right:j]; 
     } 

     if (i < right) 
     { 
      [self quickSort:arr left:i right:right]; 
     } 

    } 

} 

mais cela n'a pas aidé. De mon point de vue, quand je reçois un ensemble de NSManagedObjects, ils ne sont pas dans la mémoire vive (RAM). Mais pendant le tri, ils apparaissent dans la RAM.

Je voulais être trié NSMutableSet (essayé de définir:

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"specificImages.id" ascending:YES]; 

Mais je suis

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here' 

j'ai décrit ce problème est l'autre question NSSortDescriptor to-many relationships

De mon point de vue , Je vois 2 approches: 1) executeFetchRequest, mais fournir: les objets n'apparaissent pas dans la RAM (je ne sais pas comment, mais je suis presque shure que il est possible) 2) changer mon tri rapide pour fournir: les objets ne figurent pas dans la RAM

Mise à jour Voici mon code, où je tente d'aller chercher des objets avec executeFetchRequest (les objets sont en RAM et Je veux que ce soit des objets de défaut (pas dans la RAM)):

+ (NSMutableSet *)GetImagesWithPredicate:(NSPredicate *)predicate 
{ 
    NSString *entityName = kEntityName; 
    AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];; 
    NSManagedObjectContext *context = appDelegate.managedObjectContext; 
    NSEntityDescription *entityDesctiption = [NSEntityDescription 
               entityForName: entityName 
               inManagedObjectContext:context]; 

    // find object 
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    [request setEntity:entityDesctiption]; 
    [request setPredicate:predicate]; 
    NSArray *objects = [context executeFetchRequest:request error:nil]; 
    [request release]; 
    if (objects == nil) 
    { 
     NSLog(@"there was an error"); 
     return nil; 
    } 
    NSMutableSet *set = [NSMutableSet setWithArray:objects]; 
    return set; 
} 

où prédicat:

NSMutableArray *allID = [NSMutableArray array]; 
for (int i = 1; i < 639; i++) 
{ 
     [allID addObject:[NSNumber numberWithInt:i]]; 
} 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id in %@", allID]; 
+0

Juste un FYI, vous ne devriez pas stocker 5 Mo de données dans une seule entité/ligne. Les directives d'Apple en parlent explicitement. Les images, à moins qu'elles ne soient très petites, doivent être stockées sur le système de fichiers et seulement leur chemin doit être stocké dans l'entité. –

+0

pouvez-vous prouver un lien vers les directives Apple explicitement. Donc je peux le lire. (J'ai entendu à ce sujet, mais je veux le lire par moi-même) –

Répondre

3

tl; dr le code.

CoreData a une chose. C'est ce qu'on appelle en défaut. L'objet Fault signifie que vous avez des références à cet objet dont les données sont toujours dans le magasin (votre version de "not in RAM"). Pour désaffecter un objet, vous devez appeler la méthode valueForKey: et récupérer n'importe quelle propriété (ceci charge l'objet entier sauf pour les relations). Lors du tri, les données de base appellent en interne valueForKey: ce qui entraîne le chargement de vos données d'image.

Ma proposition pour vous: créer une entité distincte appelée quelque chose comme ImageDescriptor où vous détenir toutes les propriétés requises pour le tri. Cette entité contiendrait une relation bi-univoque avec les données d'image binaire réelles que vous ne récupéreriez que lorsque vous en auriez besoin (c'est-à-dire utiliser l'extraction paresseuse).

+0

Bonne idée, mais j'espère, il peut y avoir une autre approche: 1) cacher à nouveau toutes les données, après avoir utilisé valueForKey: 2) exécuterFetchRequest with Fault objets (qui ne sont pas dans la RAM) –

+0

1) vous ne pouvez pas blâmer un objet au milieu du tri (ceci nécessite d'appeler l'appel de méthode 'refreshObject: mergeChanges:' pour chaque objet du contexte dans lequel vous extrayez les objets.) AFAIK - 'executeFetchRequest:' récupère les objets en défaut par défaut. – Eimantas

+0

si executeFetchRequest: récupère les objets défaillants par défaut, pourquoi l'application reçoit-elle un avertissement de mémoire. Je vais mettre à jour la question pour vous. Je vais ajouter le code avec executeFetchRequest: –

0

J'ai utilisé l'approche Eimantas, mais j'ai réussi à récupérer des objets sans les enregistrer dans la RAM. J'ai utilisé includesPropertyValues

Questions connexes