具有多个并行DB-Accesses的iOS-App设计

时间:2012-01-17 08:50:13

标签: ios core-data grand-central-dispatch nsmanagedobjectcontext

在我的App中,我使用JSON内容获取请求,解析它们并将它们存储在CoreData中。在用户与DB交互的同时(读写访问)。

将数据存储到数据库后,将启动第二个任务,根据接收的数据创建新数据。我将使用Grand Central Dispatch进行解析并将数据存储到数据库中。

我的问题是,当使用GCD时,我得到一个EXC_BAD_ACCESS,这可能是由于我假设的Core Data的非线程安全性造成的。另一个错误是我在使用上下文performBlockAndWait时遇到了死锁。

我应该如何设计正确处理GCD和NSMutableContexts的应用?

------- -------- EDIT

现在我已经阅读了核心数据编程指南,我发现我必须使用线程限制模式。

我的应用程序目前以这种方式构建:我有几个管理器,每个管理器都拥有自己的上下文。但是当使用多个线程时,我发现3个线程调用同一个Manager,这意味着3个线程同时使用一个上下文。这会导致死锁。

为了解决这个问题,我想到了通过threadname创建一个上下文:

- (NSManagedObjectContext *)createManagedObjectContextWithTreadName:(NSString*) threadname {

    if([NSThread currentThread].name.length ==0){
        [NSThread currentThread].name = threadname; 
    }

    NSManagedObjectContext *context = nil;
    context = [self.contextStore objectForKey:threadname];

    if(!context){
        NSLog(@"Creating context for threadname: %@",threadname);

        NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator;
        if (coordinator != nil)
        {
            context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
            context.persistentStoreCoordinator = coordinator;
            context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;

            NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
            [nc addObserver:self selector:@selector(mergeChangesFromMOC:) name:NSManagedObjectContextDidSaveNotification object:context];
            [self.contextStore setValue:context forKey:threadname];
        }
    }
    return context;
}

这是个好主意吗?

2 个答案:

答案 0 :(得分:3)

答案 1 :(得分:2)

好的 - 这就是我解决它的方法:

+(NSManagedObjectContext *)managedObjectContext {
    AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    NSManagedObjectContext *moc = delegate.managedObjectContext;

    NSThread *thread = [NSThread currentThread];

    if ([thread isMainThread]) {
        return moc;
    }

    // a key to cache the context for the given thread
    NSString *threadKey = [NSString stringWithFormat:@"%p", thread];

    // delegate.managedObjectContexts is a mutable dictionary in the app delegate
    NSMutableDictionary *managedObjectContexts = delegate.managedObjectContexts;

    if ( [managedObjectContexts objectForKey:threadKey] == nil ) {
        // create a context for this thread
        NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 

        threadContext.persistentStoreCoordinator = [moc persistentStoreCoordinator];
        threadContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;

        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc addObserver:self selector:@selector(mergeChangesFromMOC:) name:NSManagedObjectContextDidSaveNotification object:threadContext];

        // cache the context for this thread
        [managedObjectContexts setObject:threadContext forKey:threadKey];
        //NSLog(@"MocCount: %d",managedObjectContexts.count);
    }

    return [managedObjectContexts objectForKey:threadKey];
}

+ (void)mergeChangesFromMOC:(NSNotification *)aNotification {

    //NSLog(@"Performing a merge of managed object context in class %@",[self class]);

    @try {
        AppDelegate *delegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
        NSManagedObjectContext *moc = delegate.managedObjectContext;
        [moc mergeChangesFromContextDidSaveNotification:aNotification];


        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:[aNotification object]];      
    }
    @catch (NSException * e) {
        NSLog(@"Stopping on exception: %@", [e description]);
    }
    @finally {}
}

我需要一个上下文,我问[ContainingClass managedObjectContext]并获取主线程或我所在线程的上下文。当需要合并时,这将在主线程上执行。