web-dev-qa-db-fra.com

Application multithread Core Data

J'essaie d'utiliser les données de base de manière multi-thread. Je veux simplement montrer l'application avec les données précédemment téléchargées tout en téléchargeant 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 télécharge le fichier de manière asynchrone en utilisant délégué (et montrant la progression), puis j'utilise un XMLParser pour analyser les nouvelles données et créer de nouveaux NSManagedObjects dans un contexte séparé, avec son propre persistentStore et en utilisant un thread séparé.

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

Paolo aka SlowTree

62
SlowTree

Le Apple Concurrence avec la documentation Core Data est le point de départ. Lisez-le très attentivement ... J'ai été mordu plusieurs fois par mes malentendus!

Les règles de base sont les suivantes:

  1. Utilisez un NSPersistentStoreCoordinator par programme. Vous n'en avez pas besoin par thread.
  2. Créez un NSManagedObjectContext par thread.
  3. Ne passez jamais un NSManagedObject sur un thread à l'autre thread.
  4. Au lieu de cela, obtenez les ID d'objet via -objectID et passez-le à l'autre thread.

Plus de règles:

  1. Assurez-vous d'enregistrer l'objet dans le magasin avant d'obtenir l'ID d'objet. Tant qu'ils ne sont pas enregistrés, ils sont temporaires et vous ne pouvez pas y accéder à partir d'un autre fil.
  2. Et méfiez-vous des stratégies de fusion si vous apportez des modifications aux objets gérés à partir de plusieurs threads.
  3. NSManagedObjectContext's -mergeChangesFromContextDidSaveNotification: est utile.

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

149
Yuji

Actuellement [mai 2015] le documentation Apple Concurrency avec Core Data est, au mieux, très trompeur car il ne couvre aucune des améliorations dans iOS 5 et ne montre donc plus les meilleures façons d'utiliser le noyau simultanément. Il y a deux changements très importants dans iOS 5 - les contextes parents et les nouveaux types de concurrence/threading.

Je n'ai pas encore trouvé de documentation écrite couvrant ces nouvelles fonctionnalités, mais la Vidéo WWDC 2012 "Session 214 - Core Data Best Practices" l'explique très bien.

Magical Record utilise ces nouvelles fonctionnalités et peut valoir le coup d'œil.

Les vraies bases sont toujours les mêmes - vous ne pouvez toujours utiliser que les objets gérés sur lesquels le contexte de leur objet géré a été créé.

Vous pouvez maintenant utiliser [moc performBlock:] pour exécuter du code sur le thread droit.

Il n'est plus nécessaire d'utiliser mergeChangesFromContextDidSaveNotification: plus; créez plutôt un contexte enfant pour effectuer les modifications, puis enregistrez le contexte enfant. L'enregistrement du contexte enfant repoussera automatiquement les modifications dans le contexte parent, et pour enregistrer les modifications sur le disque, effectuez simplement une sauvegarde sur le contexte parent dans son thread.

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

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

Puis sur le fil de fond:

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 ...>
    }
}];
76
JosephH

J'espère que cela peut aider tous les peuples qui rencontrent des problèmes à utiliser les données de base dans un environnement multithread.

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

J'espère que cela t'aides.

Paolo

p.s. Un grand merci à Yuji, dans la documentation que vous avez décrite ci-dessus, j'ai trouvé cet exemple.

2
SlowTree