1

我在后台 GCD 线程中遇到核心数据问题...我想更新一条记录,但在获取它并设置值之后,它似乎并没有真正保存更新的记录。

isUpdate是我设置的 BOOL,它告诉我是否正在运行第一次解析/保存,或者它是否是我需要更新的记录。就我而言,当我更新一条记录时,它实际上似乎并没有在我的商店中更新。

我正在使用 MagicalRecord 助手。这是我的代码:

// Create background context
NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] init];
[backgroundContext setPersistentStoreCoordinator:[NSPersistentStoreCoordinator defaultStoreCoordinator]];
// Save the background context and handle the save notification
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(backgroundContextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:backgroundContext];

// Parsing data...
//..

Record *record;
if (!isUpdate) {
    record = [NSEntityDescription insertNewObjectForEntityForName:@"Record" inManagedObjectContext:backgroundContext];
} else {
    NSPredicate *recordPredicate = [NSPredicate predicateWithFormat:@"SELF.tag == %@", [[node attributeForName:@"tag"] stringValue]];
    record = [Record findFirstWithPredicate:recordPredicate];
}
[record setTitle:[[recordNode attributeForName:@"title"] stringValue]];

// Parsing other data...
//..

NSError *error = nil;
// save the context
[backgroundContext save:&error];
if (error) {
    NSLog(@"An error occurred: %@", error);
}

这是通知:

- (void)backgroundContextDidSave:(NSNotification *)notification {
    // Make sure we're on the main thread when updating the main context
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
                           withObject:notification
                        waitUntilDone:NO];
        return;
    }
    // merge in the changes to the main context on the main thread
    [[NSManagedObjectContext defaultContext] mergeChangesFromContextDidSaveNotification:notification];
}
4

2 回答 2

2

你的代码对我来说听起来很奇怪。

为什么要NSManagedObjectContextDidSaveNotification在后台线程中注册通知?也许我错了,但您需要在应用程序的不同位置注册该通知。

如果你想让它工作,你可以在主线程中注册该通知。例如,您可以在AppDelegate.

例如在didFinishLaunchingWithOptions:你可以做的方法中

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(backgroundContextDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:backgroundContext];

然后,始终在 中AppDelegate,您可以将更改与您编写的方法合并:

- (void)backgroundContextDidSave:(NSNotification *)notification {
    // Make sure we're on the main thread when updating the main context
    if (![NSThread isMainThread]) {
        [self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
                           withObject:notification
                        waitUntilDone:YES];
        return;
    }
    // merge in the changes to the main context on the main thread
    [[NSManagedObjectContext defaultContext] mergeChangesFromContextDidSaveNotification:notification];
}

代码执行以下步骤:

  1. 首先检查您是否在主线程中运行。
  2. 由于您注册的通知可能来自与主线程不同的线程,因此您需要在主线程上执行选择器。
  3. 最后与包含您在后台所做的更改的通知执行合并。

完成后,您可以看到主上下文已更新为在另一个上下文中所做的更改。

编辑

也许您也可以尝试将其更改waitUntilDone为 YES。

希望能帮助到你。

于 2012-05-01T22:36:54.990 回答
1

您正在混合两种情况。这段代码可能很糟糕:

 record = [Record findFirstWithPredicate:recordPredicate];

我假设这会在不同的上下文而不是你的背景上下文中找到记录。你应该把它改成这样:

 record = [Record findFirstWithPredicate:recordPredicate inManagedObjectContext:backgroundContext];
于 2012-05-02T14:06:07.640 回答