66 votes

Application multithread Core Data

Je suis en train d'utiliser de base de données dans un environnement multi thread. Je veux simplement montrer l'application avec les données précédemment téléchargées pendant le téléchargement de nouvelles données en arrière-plan. Cela devrait permettre à l'utilisateur d'accéder à l'application pendant le processus de mise à jour.

J'ai un NSURLConnection qui de télécharger le fichier asyncronously à l'aide de délégué (et en montrant le progrès), puis-je utiliser un parseur xml pour analyser les nouvelles données et de créer de nouvelles NSManagedObjects dans un autre contexte, avec ses propres persistentStore et à l'aide d'un thread séparé.

Le problème est que la création de nouveaux objets dans le même contexte de l'ancien tout en montrant qu'il peut lancers BAD_INSTRUCTION exception. Donc, j'ai décidé d'utiliser un autre contexte pour les nouvelles données, mais je ne peux pas trouver un moyen de déplacer tous les objets à l'autre contexte, une fois terminé.

Paolo aka SlowTree

157voto

Yuji Points 26887

La Pomme de Simultanéité avec la Base de Données de la documentation est l'endroit pour commencer. Lire très attentivement... j'ai été mordu à plusieurs reprises par mon malentendus!

Les règles de base sont:

  1. Utiliser un NSPersistentStoreCoordinator par programme. Vous n'avez pas besoin d'eux par thread.
  2. Créer un NSManagedObjectContext par thread.
  3. Ne dépassez jamais une NSManagedObject sur un thread à l'autre thread.
  4. Au lieu de cela, obtenir l'Id d'objet via -objectID et le transmettre à l'autre thread.

Plus de règles:

  1. Assurez-vous d'enregistrer l'objet dans le magasin avant d'obtenir l'ID de l'objet. Avant d'être sauvées, ils sont temporaires, et vous ne pouvez pas y accéder à partir d'un autre thread.
  2. Et méfiez-vous de la fusion politiques, si vous apportez des modifications à la gestion des objets de plus d'un thread.
  3. NSManagedObjectContexts' -mergeChangesFromContextDidSaveNotification: est utile.

Mais permettez-moi de répéter, veuillez lire attentivement le document! Il vaut vraiment le coup!

78voto

JosephH Points 21074

Actuellement, [octobre 2013] la Pomme de Simultanéité avec la Base de Données de la documentation est, au mieux, très trompeuse, car elle ne couvre pas toutes les améliorations que l'iOS 5 et donc n'affiche plus les meilleures façons d'utiliser la base de données simultanément. Il y a deux changements très importants dans iOS 5 - parent, de contextes et de nouvelles simultanéité/filetage types.

Je n'ai pas encore trouvé de documentation écrite qui traite de façon exhaustive de ces nouvelles fonctionnalités, mais la WWDC 2012 vidéo "Session 214 - Base de Données des Meilleures Pratiques" explique tout cela très bien.

Magique Record utilise ces nouvelles fonctionnalités et peut être en valeur un regard.

Les vrais principes de base sont toujours les mêmes -, vous pouvez toujours utiliser des objets gérés au fil de leurs géré contexte de l'objet a été créé.

Vous pouvez maintenant utiliser [moc performBlock:] pour exécuter du code sur le fil de droite.

Il n'y a pas besoin d'utiliser mergeChangesFromContextDidSaveNotification: plus; au lieu de créer un enfant de cadre pour faire les changements, puis enregistrer l'enfant contexte. Économiser de l'enfant est le contexte qui va pousser automatiquement les modifications dans le contexte parent, et pour enregistrer les modifications sur le disque, il suffit de faire une sauvegarde sur le contexte parent dans son thread.

Pour que cela fonctionne, vous devez créer le contexte parent avec un concurrent de type, par exemple:

mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

Puis sur le thread d'arrière-plan:

context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[context setParentContext:mainManagedObjectContext];

<... perform actions on context ...>

NSError *error;
if (![context save:&error])
{
    <... handle error ...>
}
[mainManagedObjectContext performBlock:^{
    NSError *e = nil;
    if (![mainContext save:&e])
    {
        <... handle error ...>
    }
}];

3voto

SlowTree Points 556

J'espère que cela pourra aider tous les peuples confrontés à des problèmes d'utilisation de données de base dans un environnement multithread.

Jetez un oeil à "Top Songs 2" dans la documentation Apple. Avec ce code, j’ai pris la "pilule rouge" de Matrix et découvert un nouveau monde, sans double erreur et sans erreur. :RÉ

J'espère que cela t'aides.

Paolo

ps Merci beaucoup à Yuji, dans la documentation que vous avez décrite ci-dessus, j'ai trouvé cet exemple.

1voto

doozMen Points 327

C'est une vieille question. Un lien vers un blog mis à jour expliquant le problème est disponible à l' adresse http://www.cimgf.com/2011/08/22/importing-and-displaying-large-data-sets-in-core-data/#more-1525

Fondamentalement, il confirme les termes décrits ici et confirme que les données de base sont très utiles dans les environnements multithreads.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X