代码之家  ›  专栏  ›  技术社区  ›  chris

多线程应用中NSManagedObjectContext的通用方法

  •  13
  • chris  · 技术社区  · 16 年前

    我在这里读了很多关于NSManagedObjectContext和多线程应用程序的文章。我还介绍了CoreDataBooks示例,以了解独立线程如何需要自己的NSManagedObjectContext,以及save操作如何与主NSManagedObjectContext合并。我发现这个例子很好,但也太具体了。我想概括一下,不知道我的方法是否合理。

    我的方法是使用一个泛型函数来获取当前线程的NSManagedObjectContext。该函数返回主线程的NSManagedObjectContext,但如果从其他线程中调用,则将创建一个新的(或从缓存中获取)。具体如下:

    +(NSManagedObjectContext *)managedObjectContext {
        MyAppDelegate *delegate = (MyAppDelegate *)[[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] init] autorelease];
            [threadContext setPersistentStoreCoordinator:[moc persistentStoreCoordinator]];
            // cache the context for this thread
            [managedObjectContexts setObject:threadContext forKey:threadKey];
        }
    
        return [managedObjectContexts objectForKey:threadKey];
    }
    

    commit 功能:

    +(void)commit {
        // get the moc for this thread
        NSManagedObjectContext *moc = [self managedObjectContext];
    
        NSThread *thread = [NSThread currentThread];
    
        if ([thread isMainThread] == NO) {
            // only observe notifications other than the main thread
            [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(contextDidSave:)
                                                     name:NSManagedObjectContextDidSaveNotification
                                                   object:moc];
        }
    
        NSError *error;
        if (![moc save:&error]) {
            // fail
        }
    
        if ([thread isMainThread] == NO) {
            [[NSNotificationCenter defaultCenter] removeObserver:self 
                                                        name:NSManagedObjectContextDidSaveNotification 
                                                      object:moc];
        }
    }
    

    contextDidSave: 犯罪 .

    +(void)contextDidSave:(NSNotification*)saveNotification {
        MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
        NSManagedObjectContext *moc = delegate.managedObjectContext;
    
        [moc performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                          withObject:saveNotification
                       waitUntilDone:YES];
    }
    

    最后,我们用以下方法清理NSManagedObjectContext的缓存:

    +(void)initialize {
        [[NSNotificationCenter defaultCenter] addObserver:self 
                                                 selector:@selector(threadExit) 
                                                     name:NSThreadWillExitNotification 
                                                   object:nil]; 
    }
    
    +(void)threadExit {
        MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
        NSString *threadKey = [NSString stringWithFormat:@"%p", [NSThread currentThread]];  
        NSMutableDictionary *managedObjectContexts = delegate.managedObjectContexts;    
    
        [managedObjectContexts removeObjectForKey:threadKey];
    }
    

    这是编译,似乎工作,但我知道线程问题可能是棘手的,由于种族条件。有人认为这种方法有问题吗?

    2 回复  |  直到 16 年前
        2
  •  0
  •   chris    16 年前

    我终于更好地理解了这个问题,找到了解决办法。我的解决方案没有直接解决上面的问题,但是解决了为什么我必须首先处理线程的问题。

    我的应用程序使用ASIHTTPRequest库处理异步请求。我从服务器获取一些数据,并使用委托 requestFinished 函数来添加/修改/删除我的核心数据对象。这个 请求已完成 函数在另一个线程中运行,我假设这是异步请求的自然副作用。

    +(NSThread *)threadForRequest:(ASIHTTPRequest *)request {
        return [NSThread mainThread];
    }
    

    请求已完成 在主线程中,这消除了我在应用程序中关心线程的需要。