2011-12-23 3 views
0

Je travaille avec Core Data pour la première fois, avec le cours de développement d'application iOS de Stanford comme guide. J'ai copié à peu près le code de l'application de démonstration (bien sûr, je l'ai ajusté à mes besoins), mais j'ai deux problèmes actuellement.Core Data ne sauvegarde pas les objets et est lent

Mon application est une vue de la carte qui, sur le robinet d'un bouton présente un contrôleur de vue modale. Cette vue modale vérifie si un UIManagedDocument a été créé. Sinon, il en crée un et insère les données. Ces données proviennent d'une liste de propriétés (258 éléments, donc rien de trop excessif). Si elle a déjà été créée (en affichant précédemment cette vue), si ma logique est vérifiée, il devrait être prudent de supposer qu'elle a aussi du contenu parce que les NSManagedObject sont créés en même temps qu'un document est créé. La première exécution fonctionne parfaitement bien, la table se charge et toutes mes données sont correctement affichées. Cependant, lorsque je rejette et ré-affiche ma vue modale, la table reste vide. Je vérifie l'état du document, qui est UIDocumentStateNormal, donc l'interroger devrait être bon. Mais ce n'est pas le cas: mon fetchedResultsController renvoie 0 lignes. Si je comprends correctement UIManagedContext, le comportement que je rencontre peut être causé par un contexte faux/différent, mais je m'assure que: 1) Je passe mon document (pas seulement le contexte) à la vue modale dans prepareForSegue:sender, et 2) Je passe mon document avec le contexte à la vue de présentation lorsque la vue modale est rejetée. C'est pourquoi je pense que ce n'est probablement pas le contexte, mais quelque chose d'autre. Une autre chose: l'insertion des 258 enregistrements lors du premier lancement de l'application est assez rapide dans le simulateur. Cependant, sur mon téléphone, cela pourrait prendre 13 secondes entières. Le code d'insertion est illustré ci-dessous (modifié pour la lisibilité):

+ (Department *)departmentName:(NSString *)name 
       withAttributes:(NSDictionary *)attributes 
        inContext:(NSManagedObjectContext *)context { 

    Department *department = [NSEntityDescription insertNewObjectForEntityForName:@"Department" inManagedObjectContext:context]; 
     department.name = name; 

     NSArray *informationElements = [attributes objectForKey:@"information"]; 

     for (int i = 0; i < [informationElements count]; i++) { 
      NSString *informationValue = [[informationElements objectAtIndex:i] objectForKey:@"value"]; 

      if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"phone"]) { 
       department.phone = informationValue; 
      } else if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"email"]) { 
       department.email = informationValue; 
      } else if ([[[informationElements objectAtIndex:i] objectForKey:@"description"] isEqualToString:@"web"]) { 
       department.website = informationValue; 
      } 
     } 
    return department; 
} 

Pour être clair: ce code fonctionne très bien, mais il est très lent. Il est encapsulé dans une méthode qui s'appelle exactement 258 fois. informationElements a au plus trois éléments, ce qui signifie qu'il y a 258 * 3 = 774 boucles maximum. En réalité, c'est beaucoup moins que ça, mais même si c'était 774, cela ne devrait pas prendre 13 secondes, n'est-ce pas?

L'extrait ci-dessous montre l'initialisation du UIManagedDocument:

if (![[NSFileManager defaultManager] fileExistsAtPath:[self.database.fileURL path]]) { 
    [self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) { 
     [self setupFetchedResultsController]; 
     [self fetchDepartmentsIntoDocument:self.database]; 
    }]; 
} else if (self.database.documentState == UIDocumentStateClosed) { 
    [self.database openWithCompletionHandler:^(BOOL success) { 
     [self setupFetchedResultsController]; 
    }]; 
} else if (self.database.documentState == UIDocumentStateNormal) { 
    [self setupFetchedResultsController]; 
} 

fetchDepartmentsIntoDocument lit la liste des propriétés, puis exécute une boucle qui appelle departmentName:withAttributes:inContext pour chaque élément de la liste des biens.

Si quelqu'un pouvait m'aider, ce serait très apprécié!

+0

avez-vous essayé sur un autre thread? –

+0

Je n'ai pas. Y a-t-il une chance qu'il y ait trop de données pour le gérer assez rapidement? –

+0

pourrait être, j'utilise des données de base pour enregistrer mon objet singleton et cela fonctionne bien, mais le vôtre semble beaucoup plus compliqué. Je le dis comme une sorte de déclaration générale pour quelque chose qui fonctionne mais qui est lent. sauf s'il y avait des raisons de penser autrement. –

Répondre

1

Pour le problème de vitesse, je voudrais examiner en utilisant des prédicats; cela devrait accélérer les choses beaucoup! Les prédicats font en sorte que le contexte renvoie uniquement les valeurs nécessaires en fonction du critère que vous choisissez. La raison pour laquelle ils sont plus rapides est qu'il ne doit pas convertir chaque objet d'entité stocké en un objet géré, mais qu'il peut tirer directement de la propriété, ce qui accélère les comparaisons de manière drastique.

+0

Ouais, ce serait une option, sauf que j'ai vraiment besoin de tous ces objets. C'est une table qui affiche tous les départements à partir desquels l'utilisateur peut en choisir un. S'il n'y a vraiment aucun moyen de contourner la vitesse, je vais devoir changer cela, mais pour l'instant, j'aimerais voir s'il y a autre chose que je pourrais faire pour garder mon interface utilisateur actuelle avec des vitesses inférieures à une seconde. –

0

Lorsque vous insérez des objets Département dans le contexte, enregistrez-vous pour chaque objet? L'insertion est relativement peu coûteuse, mais l'enregistrement (c'est-à-dire -[NSManagedobjectContext save:]) est coûteux (puisque la base de données doit effectuer le verrouillage et les E/S de fichier).

En outre, sur une note plus stylistique, vous pouvez le faire

for (NSDictionary *element in informationElements) { 
     NSString *informationValue = [element objectForKey:@"value"]; 

     if ([[element objectForKey:@"description"] isEqualToString:@"phone"]) { 
      department.phone = informationValue; 
     } else if ([[element objectForKey:@"description"] isEqualToString:@"email"]) { 
      department.email = informationValue; 
     } else if ([[element objectForKey:@"description"] isEqualToString:@"web"]) { 
      department.website = informationValue; 
     } 
    } 

à itérer votre gamme de dictionnaires.

+1

En fait, je comptais sur le mécanisme d'auto-sauvegarde de UIDocument, donc je n'étais pas en train de sauvegarder du tout. Même avec une sauvegarde manuelle, mes données ne sont pas stockées entre les commutateurs d'affichage. J'étais également conscient de l'énumération rapide, mais puisque ma méthode actuelle était également utilisée dans la conférence, je me suis dit que je devais l'utiliser. –

Questions connexes