ios - 核心数据后台处理,保存不推送到主上下文

标签 ios multithreading cocoa-touch core-data save

我遇到了一些核心数据后台处理的问题。当我在我的后台上下文中保存时,它似乎并没有将保存推到主上下文中。在调试代码时,我从正在执行保存操作的后台线程注意到它似乎已暂停(?)此行为导致我获取过时的对象。

来自保存的堆栈跟踪:

Thread 29, Queue : NSManagedObjectContext Queue
#0  0x9a5cf80e in semaphore_wait_trap ()
#1  0x02216f08 in _dispatch_thread_semaphore_wait ()
#2  0x02214b3a in _dispatch_barrier_sync_f_slow ()
#3  0x02214a5c in dispatch_barrier_sync_f ()
#4  0x01dfe03b in _perform ()
#5  0x01dfde9e in -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] ()
#6  0x01ddb33c in -[NSManagedObjectContext save:] ()
#7  0x00096213 in __45-[CoreDataHelper saveInManagedObjectContext:]_block_invoke_0 at /Users/peterwarbo/Documents/Projects/MessagePlanr/MessagePlanr/CoreDataHelper.m:307
#8  0x01e734b3 in developerSubmittedBlockToNSManagedObjectContextPerform_privateasync ()

保存方式:

- (void)saveInManagedObjectContext:(NSManagedObjectContext *)context {

    if (context == nil) {

        // Use default MOC
        context = self.managedObjectContext;

        NSError *error = nil;

        if (context != nil)
        {
            if ([context hasChanges] && ![context save:&error])
            {
                /*
                 Replace this implementation with code to handle the error appropriately.

                 abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                 */
                DLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }

    } else {

        // First save (child) context
        [context performBlock:^{

            NSError *error = nil;

            if ([context hasChanges] && ![context save:&error])
            {
                /*
                 Replace this implementation with code to handle the error appropriately.

                 abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                 */
                DLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }];


        // Then save parent context
        [self.managedObjectContext performBlock:^{

            NSError *error = nil;

            if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) {

                /*
                 Replace this implementation with code to handle the error appropriately.

                 abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                 */
                DLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }];
    }
}

这是保存的方法,Reminder 是一个NSManagedObject,当操作完成时我调用一个完成 block 。然而,在完成 block 中,当获取一些 NSManagedObjects 时,它们尚未更新(我认为是由于保存暂停?)

- (void)checkOverdueRemindersInBackgroundWithCompletionBlock:(void (^)(NSInteger overdueCount, NSArray *reminders))block {

    DLogName()

    // Creating a new MOC for thread safety
    NSManagedObjectContext *syncContext = [self threadedManagedObjectContext];

    [syncContext performBlock:^{

        NSArray *reminders = [self fetchEntity:APReminderEntity predicate:nil andSortDescriptors:nil inManagedObjectContext:syncContext];

        NSInteger overdueCount = 0;

        for (Reminder *reminder in reminders) {

            [reminder checkOverdue]; // Checks if object is overdue and sets a flag if it is

            [self saveInManagedObjectContext:syncContext];

            if (reminder.status.intValue == RMReminderStatusOverdue) {

                overdueCount++;
            }

        }

        block(overdueCount, reminders);
    }];
}

threadedManagedObjectContext 方法:

- (NSManagedObjectContext *)threadedManagedObjectContext {

    NSManagedObjectContext *threadedMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    threadedMoc.parentContext = self.managedObjectContext; //self.managedObjectContext is of type NSMainQueueConcurrencyType

    return threadedMoc;
}

最佳答案

出现此问题是因为我正在使用 performBlock: 进行异步保存,它会立即返回,因此当它返回并且我的完成 block 被调用时可能不会提交保存。

所以这个问题的答案是在performBlockAndWait:

中运行后台保存进程

现在出现了另一个问题,使用 performBlockAndWait: 有什么缺点吗?

关于ios - 核心数据后台处理,保存不推送到主上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14829607/

相关文章:

Python:使用 linecache 读取大量文件与普通文件访问 open()

ios - ios中的自定义字体不起作用

swift - UICollectionViewCell 仅在满足特定条件时显示

ios - Q :Controller present 2 second ,如何让它看起来只有一个转换?

c++ - fork 命令是否适用于多线程应用程序?

ios - Facebook SDK 和 Firebase

java - 如何从(非 Activity )Java 类调用 Activity 类中定义的方法

iphone - 如何使部分的 UITableView 页脚不粘

iOS - 核心数据 - NSManagedObjectContext - 不确定是否保存

iphone - 当我重新加载 UIWebView 的内容时制作翻转动画(或类似的动画)