J'écris un Core Data ContextManager pour une application iOS de plus grande taille. Un ContextManager fournit un NSManagedContext qui est automatiquement mis à jour lorsque d'autres ContextManagers enregistrent leur NSMangedContext dans le magasin de données persistantes.Données de base mergeChangesFromContextDidSaveNotification ne fonctionne pas
J'ai un test unitaire (TestContextManager) qui crée deux contextes, ajoute un objet à un et teste si l'objet apparaît dans l'autre contexte. Ce n'est pas le cas. Pourquoi le dernier test échoue-t-il?
Voici le code pour un ContextManager et le test d'unité défaillante. Le dernier assertion dans le test unitaire échoue. Tous les autres affirment passer. Comme vous pouvez le voir, le ContextManager repose sur l'obtention d'une notification de modification d'un autre ContextManager et l'utilisation de mergeChangesFromContextDidSaveNotification
pour se mettre à jour. Notez que tout se passe sur le même thread pour ce test.
Je sais que NSManagedObjectContextDidSaveNotification est envoyé et reçu correctement. Je sais que NSManagedObjectContextDidSaveNotification a les données correctes dans son dictionnaire userInfo.
J'ai également exécuté ce test unitaire en tant que test d'application sur un périphérique réel à l'aide d'un magasin persistant SQLite - le même problème échoue.
Merci d'avance!
ContextManager:
#import "ContextManager.h"
@implementation ContextManager
@synthesize context;
#pragma mark - Custom code
- (void)save {
NSError *error = nil;
if (self.context != nil) {
if ([self.context hasChanges] && ![self.context save:&error]) {
NSAssert1(FALSE, @"Unable to save the managed object context. UserInfo:\n%@", [error userInfo]);
}
}
return;
}
- (void)mergeChanges:(NSNotification *)notification {
if (notification.object != self.context) {
[self.context mergeChangesFromContextDidSaveNotification:notification];
}
return;
}
#pragma mark - Overridden NSObject methods
#pragma mark Creating, copying, and deallocating object
- (id)initWithPersistentStoreCoordinator:(NSPersistentStoreCoordinator *)persistentStoreCoordinator {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:nil];
self.context = [[[NSManagedObjectContext alloc] init] autorelease];
[self.context setPersistentStoreCoordinator:persistentStoreCoordinator];
}
return self;
}
- (void)dealloc {
[context release];
[super dealloc];
return;
}
@end
TestContextManager:
#import "TestContextManager.h"
#import "ContextManager.h"
#import "CoreDataManager.h"
#define TEST_MANAGED_OBJECT @"AManagedObject"
@implementation TestContextManager
- (void)testContextManager {
CoreDataManager *coreDataManager = [[CoreDataManager alloc] init];
coreDataManager.storeType = NSInMemoryStoreType;
ContextManager *contextManagerA = [coreDataManager provideContextManager];
if (!contextManagerA) STFail(@"CoreDataManager did not provide a context manager.");
NSManagedObjectContext *contextA = contextManagerA.context;
if (!contextA) STFail(@"ContextManager did not provide a managed object context.");
// setA1 has 0 objects (or whatever is initially there).
NSSet *setA1 = [contextManagerA.context registeredObjects];
[NSEntityDescription insertNewObjectForEntityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextManagerA.context];
// setA2 has 1 object.
NSSet *setA2 = [contextManagerA.context registeredObjects];
STAssertTrue([setA2 count] == [setA1 count]+1, @"Context provided by ContextManager is not accepting new objects.");
[contextManagerA save];
ContextManager *contextManagerB = [coreDataManager provideContextManager];
[NSEntityDescription insertNewObjectForEntityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextManagerB.context];
[contextManagerB save];
NSSet *setA3 = [contextManagerA.context registeredObjects];
// setA3 should have 2 objects <=== THIS TEST FAILS
STAssertTrue([setA3 count] == [setA1 count]+2, @"Context is not updating new objects.");
[coreDataManager release];
return;
}
@end
Oui. Ceci est fait dans la méthode initWithPersistentStoreCoordinator: de ContextManager. J'ai également utilisé la journalisation pour vérifier que les notifications sont envoyées et reçues par le ContextManager. – Erik
Oh attends j'ai juste remarqué quelque chose. Le problème n'est pas la fusion, c'est dans le test. Votre affectation à setA1 & setA2 aboutit à pointer sur le même objet. Vous devez soit faire une copie des objets enregistrés pour chacun ou simplement obtenir le nombre de chacun avant d'ajouter un nouvel objet. –
Je pense que NSManagedContext envoie et libère automatiquement NSSet en tant que valeur de retour à registeredObjects. Mais, au cas où, j'ai mis à jour mon code par mon ajout ci-dessous. Malheureusement, le test échoue toujours ... – Erik