iPhone Coredata error (NSMergeConflict for NSManagedObject))
parfois j'ai cette erreur avec coredata au même endroit. Parfois, c'est ok, et en d'autres temps, j'ai cette erreur. Ça veut dire quoi? Je ne trouve rien :(
ps désolé pour mon anglais :)
conflictList = ( "NSMergeConflict (0xd447640) pour NSManagedObject (0xd41b370) avec objectID '0xd41b500' avec oldVersion = 4 et nouvelleversion = 5 et de l'ancien objet instantané = {n album = "{(n)}";n audios = "{(n)}";n bdate = "";n ville = "";n pays = "";n dialogue = "{(n)}";n domaine = "blanc.la fumée";n faculté = 0;n facultyName = "";n prenom = Blanc;n graduation = 0;n homePhone = "";n isFriend = 1;n isMe = 0;n lastName = Fumée;n mobilePhone = "";n pseudo = "";n ligne = 1;n photo = "";n photoBig = "";n photoComments = "{(n)}";n photoMedium = "";n photoRec = "http://cs10609.vkontakte.ru/u79185807/e_8c949409.jpg";n photos = "{(n (entité: Photo; id: 0xd482c50 ; données: {n aid = 121594781;n album = nil;n commentaires = \"\";n commentsCount = 0;n créé = \"2010-12-10 03:45:01 GMT\";n propriétaire = \"0xd41b500 \";n \"owner_id\" = 79185807;n photosNumber = 0;n pid = 196997145;n src = \"http://cs10609.vkontakte.ru/u79185807/121594781/m_\";n \"src_big\" = \"http://cs10609.vkontakte.ru/u79185807/121594781/x_\";n \"src_small\" = \"http://cs10609.vkontakte.ru/u79185807/121594781/s_\";n \"src_xbig\" = nil;n \"src_xxbig\" = nil;n wallRel = \"0xd480840 \";n}),n (entité: Photo; id: 0xd431570 ; données: {n aid = 121594781;n album = nil;n commentaires = \"\";n commentsCount = 0;n créé = \"2010-12-10 03:43:01 GMT\";n propriétaire = \"0xd41b500 \";n \"owner_id\" = 79185807;n photosNumber = 0;n pid = 196997029;n src = \"http://cs10609.vkontakte.ru/u79185807/121594781/m_\";n \"src_big\" = \"http://cs10609.vkontakte.ru/u79185807/121594781/x_\";n \"src_small\" = \"http://cs10609.vkontakte.ru/u79185807/121594781/s_\";n \"src_xbig\" = nil;n \"src_xxbig\" = nil;n wallRel = \"0xd42d500 \";n})n)}";n = "de 19";n sexe = 0;n statuts = "{(n)}";n timezone = 0;n uid = 79185807;n université = 0;n universityName = "";n vidéos = "{(n)}";n mur = "{(n)}";n wallPostsCount = 0;n wallReplies = "{(n (entité: WallReply; id: 0xd448270 ; données: )n)}";n wallSender = "{(n)}";n} et de nouveau mis en cache row = {n bdate = "";n ville = "";n pays = "";n domaine = "blanc.la fumée";n faculté = 0;n facultyName = "";n prenom = Blanc;n graduation = 0;n homePhone = "";n isFriend = 1;n isMe = 0;n lastName = Fumée;n mobilePhone = "";n pseudo = "";n ligne = 1;n photo = "";n photoBig = "";n photoMedium = "";n photoRec = "http://cs10609.vkontakte.ru/u79185807/e_8c949409.jpg";n = "de 19";n sexe = 0;n timezone = 0;n uid = 79185807;n université = 0;n universityName = "";n wallPostsCount = 0;n}" );
5 réponses
un conflit de fusion résulte parfois lorsque votre base de données est modifiée à partir de deux endroits différents, puis sauvegardée à partir de deux endroits différents; dans certains cas, les modifications peuvent affecter les mêmes objets ou propriétés, et les données de base ne les écrasent pas automatiquement, car cela pourrait détruire des données précieuses.
Il y a quelques options:
- lorsque vous obtenez un conflit de fusion, itérez à travers ses informations, et résoudre manuellement tous les conflits selon les besoins de votre application.
- définir la Politique de fusion de l'objet géré contexte(s) de celui qui va résoudre automatiquement certains types de conflits. Certaines politiques de fusion sont partiellement destructrices, d'autres sont très destructrices – ce qui est juste dépend vraiment de votre application et de l'importance des données sauvegardées.
- Utiliser mergeChangesFromContextDidSaveNotification: pour intégrer rapidement et étroitement les changements dans les contextes d'objets gérés qui n'ont pas encore été enregistrée. Il est à noter que cela peut exiger un certain niveau de résolution des conflits, mais devrait aider à réduire au minimum la gravité.
j'ai eu le même conflit de fusion, tout en sauvegardant le contexte. voir apple doc ici
j'ai résolu les conflits en utilisant NSMergePolicy
- (BOOL)resolveConflicts:(NSArray *)list error:(NSError **)error
définir policyType à NSOverwriteMergePolicyType
tout en créant l'objet NSMergePolicy
NSOverwriteMergePolicyType: spécifie une politique qui remplace l'état dans le magasin persistant pour les objets modifiés en conflit.
`
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
NSArray * conflictListArray = (NSArray*)[[error userInfo] objectForKey:@"conflictList"];
NSLog(@"conflict array: %@",conflictListArray);
NSError * conflictFixError = nil;
if ([conflictListArray count] > 0) {
NSMergePolicy *mergePolicy = [[NSMergePolicy alloc] initWithMergeType:NSOverwriteMergePolicyType];
if (![mergePolicy resolveConflicts:conflictListArray error:&conflictFixError]) {
NSLog(@"Unresolved conflict error %@, %@", conflictFixError, [conflictFixError userInfo]);
NSLog(@"abort");
abort();
}
} }
en résumé - activer la Politique de fusion ajoutez ceci à votre configuration MOC:
objective-C
[_managedObjectContext setMergePolicy:[[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType]];
Swift
lazy var managedObjectContext: NSManagedObjectContext? = {
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
//add this line
managedObjectContext.mergePolicy = NSMergePolicy(mergeType: NSMergePolicyType.MergeByPropertyObjectTrumpMergePolicyType);
return managedObjectContext
}()
C'est semisolving, peut-être :) Par exemple, vous avez le code suivant, qui existe dans N objets (chacun d'eux est dans un thread séparé et est créé en même temps (+- 10ms)):
[coreObject addLinkedObject:linkedObject1];
NSOverwriteMergePolicy, vous aurez Dernière-En-Modifications: seul le dernier objet ajouter un lien, parce que chaque contexte sont instantané de la mémoire de stockage permanent. Ainsi, chaque instantané sont créés dans le moment temporel de la création routinière d'un objet. Le délai de traitement de 70ms cause cette information de coreObject est trop vieux, lorsque vous l'enregistrez. En d'autres termes, vous n'aurez qu'un lien enregistré ou une erreur de fusion. Bien sûr, vous pouvez vous inscrire sur NSManagedObjectContextObjectsDidchangenotification mais dans ce cas, vous aurez N! relations souscrites ou vous pouvez vous abonner en star manner à travers le contexte principal dans le fil principal, mais parfois cela n'a pas fonctionné (J'utilise MagicalRecord, Copyright 2011 Magical Panda Software LLC.).
Ma solution est de re-lire la critique coreObject juste avant de l'enregistrer en tant que bien que l'utilisation appropriée de la politique de fusion:
@synchronized (self) {
if ([context hasChanges]) {
if (needRefresh) {
[context refreshObject:coreObject mergeChanges:NO];
[coreObject addLinkedObject:linkedObject1];
}
NSError *err = nil;
[context save:&err];
if (err) {
NSLog(@"Error Saving Linked Object: %@", [err userInfo]);
[context rollback];
}
}
}
Dans ce cas, le risque est minime.
Swift 4
private(set) lazy var mainContext: NSManagedObjectContext = {
let context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.parent = privateContext
context.mergePolicy = NSMergePolicy(merge: .overwriteMergePolicyType)
// Or we can use Trumping
// .mergeByPropertyObjectTrumpMergePolicyType
// .mergeByPropertyStoreTrumpMergePolicyType
// Rolling back is another option
// .rollbackMergePolicyType
return context
}()