Слияние основных данныхChangesFromContextDidSaveNotification не работает - PullRequest
1 голос
/ 07 апреля 2011

Я пишу Core Data ContextManager для более крупного приложения iOS.ContextManager предоставляет NSManagedContext, который автоматически обновляется, когда другие ContextManager сохраняют свой NSMangedContext в постоянном хранилище данных.

У меня есть модульный тест (TestContextManager), который создает два контекста, добавляет объект в один и тестирует, чтобы увидетьесли объект появляется в другом контексте.Это не так. Почему последний тест не пройден?

Вот код для ContextManager и неудачного модульного теста.Последнее утверждение в модульном тесте не выполняется.Все остальные утверждения проходят.Как вы можете видеть, ContextManager полагается на получение уведомления об изменении от другого ContextManager и использование mergeChangesFromContextDidSaveNotification для обновления.Обратите внимание, что все происходит в том же потоке для этого теста.

Я знаю, что NSManagedObjectContextDidSaveNotification отправляется и принимается правильно.Я знаю, что NSManagedObjectContextDidSaveNotification содержит правильные данные в своем словаре userInfo.

Я также запустил этот модульный тест как тест приложения на реальном устройстве с использованием постоянного хранилища SQLite - то же самое утверждение не удалось.

Заранее спасибо!

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

Ответы [ 2 ]

1 голос
/ 07 апреля 2011

Спасибо малоизвестному за ответ на мой вопрос.Ясно, что мне нужно почитать, что на самом деле возвращает registeredObjects.Полагаю, хорошие новости заключаются в том, что реальный код работает - модульный тест был неудачным ...

Вот модульный тест, который корректно выполняет тестируемый модуль И проходит:

#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.");

    NSEntityDescription *entityDescriptionA = [NSEntityDescription entityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextA];

    // make A1 request on an empty context (0 objects)
    NSFetchRequest *requestA1 = [[NSFetchRequest alloc] init];
    [requestA1 setEntity:entityDescriptionA];
    NSError *errorA1 = nil;
    NSArray *arrayA1 = [contextA executeFetchRequest:requestA1 error:&errorA1];
    if (arrayA1 == nil) STFail(@"Fetch request A1 failed.");
    if ([arrayA1 count] != 0) STFail(@"Context A1 is not empty at start of test.");

    // add an object to context A and make request A2
    [NSEntityDescription insertNewObjectForEntityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextManagerA.context];
    NSFetchRequest *requestA2 = [[NSFetchRequest alloc] init];
    [requestA2 setEntity:entityDescriptionA];
    NSError *errorA2 = nil;
    NSArray *arrayA2 = [contextA executeFetchRequest:requestA2 error:&errorA2];
    if (arrayA2 == nil) STFail(@"Fetch request A2 failed.");
    if ([arrayA2 count] != 1) STFail(@"Context A2 did not successfully add an object.");

    // add an object to context B and make request B1
    ContextManager *contextManagerB = [coreDataManager provideContextManager];
    NSManagedObjectContext *contextB = contextManagerB.context;
    NSEntityDescription *entityDescriptionB = [NSEntityDescription entityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextB];
    [NSEntityDescription insertNewObjectForEntityForName:TEST_MANAGED_OBJECT inManagedObjectContext:contextManagerB.context]; 
    NSFetchRequest *requestB1 = [[NSFetchRequest alloc] init];
    [requestB1 setEntity:entityDescriptionB];
    NSError *errorB1 = nil;
    NSArray *arrayB1 = [contextB executeFetchRequest:requestB1 error:&errorB1];
    if (arrayB1 == nil) STFail(@"Fetch request B1 failed.");
    if ([arrayB1 count] != 1) STFail(@"Context B1 did not successfully add an object.");

    // save contextB
    [contextManagerB save];

    // check if contextA was updated
    NSFetchRequest *requestA3 = [[NSFetchRequest alloc] init];
    [requestA3 setEntity:entityDescriptionA];
    NSError *errorA3 = nil;
    NSArray *arrayA3 = [contextA executeFetchRequest:requestA3 error:&errorA3];
    if (arrayA3 == nil) STFail(@"Fetch request A3 failed.");
    if ([arrayA3 count] != 2) STFail(@"Context A did not update correctly.");

    [requestA1 release];
    [requestA2 release];
    [requestB1 release];
    [requestA3 release];
    [coreDataManager release];    

    return;
}

@end
1 голос
/ 07 апреля 2011

Вы на самом деле настроили ContextManager для наблюдения за уведомлением о сохранении управляемогоObjectContext?Вы не показываете это здесь, поэтому я просто хотел охватить простейший случай.

Извините , я должен был сделать этот комментарий к сообщению Эрика.

...