57 votes

Comment copier ou déplacer un NSManagedObject d'un contexte à un autre?

J'ai ce que je suppose est assez standard de l'installation, avec un pavé MOC qui n'est jamais enregistré (contenant un ensemble d'objets téléchargés à partir du web) et un autre permanent MOC qui persiste objets. Lorsque l'utilisateur sélectionne un objet à partir de scratchMOC à ajouter à sa bibliothèque, je veux 1) supprimer l'objet de scratchMOC et insérez-les dans permanentMOC, ou 2) une copie de l'objet dans permanentMOC. La Base de Données FAQ dit que je peux copier un objet comme ceci:

NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *copy = [context2 objectWithID:objectID];

(Dans ce cas, contexte2 serait permanentMOC.) Cependant, quand je fais cela, l'objet copié est reproché; les données sont d'abord en suspens. Lorsqu'il est réglé, plus tard, toutes les valeurs sont nuls; aucune des données (attributs ou relations) à partir de l'original managedObject sont réellement copiés ou référencé. Donc je ne vois aucune différence entre l'utilisation de cette objectWithID: méthode et seulement l'insertion d'un nouvel objet dans permanentMOC à l'aide de insertNewObjectForEntityForName:.

Je me rends compte que je peux créer un nouvel objet dans permanentMOC et copier manuellement chaque paire clé-valeur de l'objet ancien, mais je ne suis pas très heureux avec cette solution. (J'ai un certain nombre de différents objets gérés pour lequel j'ai ce problème, donc je ne veux pas avoir à rédiger et mettre à jour la copie: méthodes pour le tout comme je continue à se développer.) Est-il un meilleur moyen?

57voto

Marcus S. Zarra Points 32178

Tout d'abord, plus d'un NSManagedObjectContext sur un seul thread est pas une configuration standard. 99% du temps, vous avez seulement besoin d'un contexte et qui permettra de résoudre ce problème pour vous.

Pourquoi avez-vous besoin de plus d'un NSManagedObjectContext?

Mise à jour

C'est en fait l'un des quelques cas d'utilisation que j'ai vu où cela a du sens. Pour ce faire, vous devez faire une copie récursive de l'objet à partir d'un contexte à l'autre. Le flux de travail serait comme suit:

  1. Créer un nouvel objet dans le contexte permanent
  2. obtenez un dictionnaire des attributs de l'objet source (utilisation -dictionaryWithValuesForKeys et -[NSEntityDescription attributesByName] pour ce faire.
  3. définir le dictionnaire des valeurs sur l'objet cible (à l'aide d' -setValuesForKeysWithDictionary)
  4. Si vous avez des relations, vous aurez besoin de faire cette copie récursivement et marcher dans les relations soit codé en dur (pour éviter certains de logique circulaire) ou à l'aide de l' -[NSEntityDescription relationshipsByName]

Comme mentionné par un autre, vous pouvez télécharger les exemples de code à partir de mon livre de La Pragmatique Programmeurs de Base de Données du Livre et de voir une solution à ce problème. Bien sûr, dans le livre que j'ai en discuter plus en profondeur :)

10voto

TechZen Points 52692

La documentation est trompeuse et incomplète. L'objectID les méthodes ne sont pas eux-mêmes la copie des objets-ils tout simplement de garantir que vous avez obtenu à l'objet spécifique que vous vouliez.

L' context2 dans l'exemple est en fait la source de contexte et non pas la destination. Vous êtes l'obtention d'un néant, puisque la destination contexte n'a pas d'objet ID.

La copie d'objets gérés est assez impliqués en raison de la complexité de l'objet graphique et la façon dont le contexte de gérer le graphique. Vous n'avez pas à recréer l'objet copié en détail dans le nouveau contexte.

Voici un exemple de code que j'ai coupé à partir de l'exemple de code pour La Pragmatique du Programmeur de Base de Données: Pomme d'API pour la Persistance des Données sur Mac OS X. (Vous pourriez être en mesure de télécharger l'ensemble du projet de code sans avoir à acheter le livre à la Pragmatique du site.) Il devrait vous fournir une idée approximative de la façon d'aller sur la copie d'un objet entre le contexte.

Vous pouvez créer un certain code de base que des copies des objets, mais les détails de chaque objet graphique des relations de l'signifie généralement que vous avez à personnaliser pour chaque modèle de données.

7voto

Anthony Points 51

Avait le même problème que moi et a trouvé cet article sur le créé déconnecté des entités qui pourraient plus tard être ajouté au contexte: http://locassa.com/temporary-storage-in-apples-coredata/

L'idée est que vous avez une NSManagedObject parce que vous allez être de stocker des objets dans la base de données. Mon problème était que beaucoup de ces objets sont téléchargés par l'intermédiaire de l'API HTTP et je veux jeter la plupart d'entre eux à la fin de la session. Pensez à un flux de messages de l'utilisateur, et je ne veux sauver ceux qui ont été ajoutés à vos favoris ou enregistré en tant que brouillon.

Je crée tous mes messages à l'aide de

+ (id)newPost {
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:self.managedObjectContext];
    Post *post = [[Post alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:nil];
    return post;
}

et alors les postes sont insérés les locaux gérés contexte de l'objet lorsqu'ils sont ajoutés à vos favoris

+ (BOOL)favoritePost:(Post *)post isFavorite:(BOOL)isFavorite
{
    // Set the post's isFavorite flag
    post.isFavorite = [NSNumber numberWithBool:isFavorite];

    // If the post is being favorited and not yet in the local database, add it
    NSError *error;
    if (isFavorite && [self.managedObjectContext existingObjectWithID:post.objectID error:&error] == nil) {
        [self.managedObjectContext insertObject:post];
    }
    // Else if the post is being un-favorited and is in the local database, delete it
    else if (!isFavorite && [self.managedObjectContext existingObjectWithID:post.objectID error:&error] != nil) {
        [self.managedObjectContext deleteObject:post];
    }

    // If there was an error, output and return NO to indicate a failure
    if (error) {
        NSLog(@"error: %@", error);
        return NO;
    }

    return YES;
}

Espérons que cela aide.

1voto

Alex Points 19842

Vous devez vous assurer que vous êtes en train d'enregistrer le contexte qu' managedObject vit dans. Afin de récupérer le même objet dans un contexte différent, il doit être présent dans le magasin persistant.

Selon la documentation, objectWithID: renvoie toujours à un objet. Donc, le fait que la faute correspond à un objet de tous les nil valeurs implique qu'il n'est pas de trouver votre objet dans le magasin persistant.

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