0

使用我有没有崩溃,如果我执行运行的核 - 数据应用取回内部viewDidLoad这样的:CoreData取崩溃如果与dispatch_async

- (void) performCoreDataFetch { 
    NSError *error; 
    if (![[self fetchedResultsController] performFetch:&error]) { 
     exit(-1); // Fail 
    } 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self performCoreDataFetch]; 
} 

与执行取的上述方式唯一的问题是,如果要返回的数据很大,它冻结了几秒钟的应用程序(但确实会返回正确的结果,而不会每次崩溃),所以为了避免这种情况,我决定使用dispatch_async(代码如下所示)并在其中调用[self performCoreDataFetch]

但如果我中viewDidLoad中执行与此相同[自performCoreDataFetch] dispatch_sync 里面,像图所示,:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     [self performCoreDataFetch]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self.tableView reloadData]; 
     }); 
    }); 

调用dispatch_async内[self performCoreDataFetch]崩溃的应用程序随机说: “-[NSFetchRequest fetchLimit]: message sent to deallocated instance

我fetchedResultsController方法如下所示:

- (NSFetchedResultsController *)fetchedResultsController { 
    if (fetchedResultsController != nil) { 
     return fetchedResultsController; 
    } 

    // Create and configure a fetch request with the Organization entity 
    NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
    request.entity = [NSEntityDescription entityForName:@"Organization" inManagedObjectContext:managedObjectContext]; 
    request.fetchBatchSize = 20; 

    // create sortDescriptor array 
    NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)]; 
    NSArray *sortDescriptorArray = [NSArray arrayWithObjects:nameDescriptor, nil]; 
    request.sortDescriptors = sortDescriptorArray; 

    NSPredicate *predicate = nil; 

    predicate = [NSPredicate predicateWithFormat:@"state LIKE %@", filterByState]; 
    [request setPredicate:predicate]; 

    // Create and initialize the fetchedResultsController 
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc ] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:@"uppercaseFirstLetterOfName" cacheName:nil]; 

    self.fetchedResultsController = aFetchedResultsController; 
    fetchedResultsController.delegate = self; 

    // Memory management 
    filterByState = nil; 
// [sortDescriptorArray release]; 
    [nameDescriptor release]; 
// [predicate release]; 
    [request release]; 
    [aFetchedResultsController release]; 

    return fetchedResultsController; 

} 
+0

你想完成什么?您不应该自己调用'performFetch'方法... – Mundi 2012-03-31 21:55:12

+0

没有performFetch,我不知道执行核心数据提取的另一种方式。 – Stealth 2012-03-31 22:18:59

+0

你想完成什么?如果您懒惰地初始化抓取的结果控制器,则会在那里完成抓取,无需您自己调用performFetch。再一次,你想要做什么取回? – Mundi 2012-04-01 08:07:22

回答

3

如果您执行fetchedResultsController的提取操作,则核心数据不是线程安全的。它是有道理的,因为fetchedResultsController是你的UI的数据源。而不是执行提取,将您的fetchedResultsController设置为nil并重新加载您的tableView。

+0

你是说我的nsfetchedResultsController方法内,我应该始终将fetchedResultsController设置为零? – Stealth 2012-04-01 17:36:57

+0

不需要。您需要更新表格时,将其设置为“nil”。表更新会自动调用你的'fetchedResultsController'方法,它会懒惰地创建一个新方法。 (看看这个方法,看看它是如何工作的。) – Mundi 2012-04-01 21:32:52

1

核心数据不是线程保存。更准确地说,NSManagedObjectContext不保存。所有NSManagedObject都属于特定的NSManagedObjectContext,它们不可互换。

Pre IOS 5你需要把真正复杂的方法。基本上每个线程需要它自己的NSManagedContext

IOS5后,你可以这样做:

__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

然后你就可以在任何线程不是主线程做

[__managedObjectContext performBlock ^{ 
    //Some really long operation 
}] 

这将在一个不同的线程上做,但是以线程保存的方式。基本上核心数据会将你的操作放入队列中,并且它会逐个执行,为每个操作锁定managedObjectContext。