2014-05-05 43 views
-1

我是iOS编程新手,我一直在使用GCD初始化Core Data堆栈。 我已经试过(代码AppDelegate.m): 如何同时初始化核心数据堆栈?

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
bgQueue = dispatch_queue_create("com.example.coredata.init", DISPATCH_QUEUE_SERIAL); 
    dispatch_async(bgQueue, ^{ 
     NSPersistentStoreCoordinator *psc = [self persistentStoreCoordinator]; 
     _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     [_managedObjectContext setPersistentStoreCoordinator:psc]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      _mainThreadManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
      [_mainThreadManagedObjectContext setParentContext:_managedObjectContext]; 
      UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; 
      MasterViewController *controller = (MasterViewController *)navigationController.topViewController; 
      controller.managedObjectContext = _mainThreadManagedObjectContext; 
     }); 
    }); 
} 

然而,dispatch_async内的块(dispatch_get_main_queue())不执行和应用失败,错误“无不是合法的NSManagedObjectContext参数“当应用程序的其他部分试图使用NSManagedObjectContext时。

那么,我应该在哪里初始化核心数据对象?也许在MasterViewController中?或者有可能等待NSManagedObjectContext初始化?感谢帮助。

+1

您确定您没有比赛条件吗?你正在调度这个块异步...我猜想别的东西正在利用它,在块完成之前。您始终可以使用dispatch_semaphore来表示上下文已初始化。 – smyrgl

回答

0

目前尚不清楚你为什么这样用GCD这样做。我相信最常见的模式是懒惰地设置核心数据栈,就像苹果在大多数例子中一样。如果您在创建项目时选中“使用核心数据”框,您可以在主/明细项目的默认Xcode模板中看到它。

在AppDelegate中,您会看到类似下面粘贴的代码。无论何时使用,都会设置堆栈。所以不需要与GCD做同步。

- (NSManagedObjectContext *)managedObjectContext 
{ 
    if (_managedObjectContext != nil) { 
     return _managedObjectContext; 
    } 

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
    if (coordinator != nil) { 
     _managedObjectContext = [[NSManagedObjectContext alloc] init]; 
     [_managedObjectContext setPersistentStoreCoordinator:coordinator]; 
    } 
    return _managedObjectContext; 
} 

// Returns the managed object model for the application. 
// If the model doesn't already exist, it is created from the application's model. 
- (NSManagedObjectModel *)managedObjectModel 
{ 
    if (_managedObjectModel != nil) { 
     return _managedObjectModel; 
    } 
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataStack" withExtension:@"momd"]; 
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; 
    return _managedObjectModel; 
} 

// Returns the persistent store coordinator for the application. 
// If the coordinator doesn't already exist, it is created and the application's store added to it. 
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 
{ 
    if (_persistentStoreCoordinator != nil) { 
     return _persistentStoreCoordinator; 
    } 

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataStack.sqlite"]; 

    NSError *error = nil; 
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&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. 

     Typical reasons for an error here include: 
     * The persistent store is not accessible; 
     * The schema for the persistent store is incompatible with current managed object model. 
     Check the error message to determine what the actual problem was. 


     If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. 

     If you encounter schema incompatibility errors during development, you can reduce their frequency by: 
     * Simply deleting the existing store: 
     [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] 

     * Performing automatic lightweight migration by passing the following dictionary as the options parameter: 
     @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} 

     Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. 

     */ 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     abort(); 
    }  

    return _persistentStoreCoordinator; 
} 

我也会鼓励你看看我这篇文章:其中讨论的方式来构建自己的核心数据堆栈很好https://www.cocoanetics.com/2012/07/multi-context-coredata/。它有一个很好的基础。 (见建议堆栈的图片)enter image description here

+0

我知道这个Xcode模板。它是不是阻止主线程?顺便说一下,我看过这篇文章。当然,它回答了问题**如何初始化,但不回答**在哪里**问题。 – OwnSome

+0

就是,请参阅我提到的创建非阻塞和固定解决方案的blogpost。它是构建它的推荐方法。 你也可以看看马库斯。 S. Zarra关于核心数据的书。他还建议这种模式,并在博客上发表评论。它是一本关于Core Data的热门书籍,可能也值得作为iOS的新手加入。 – oehman

+0

我个人经常设置一个AppName单例,在那里保留我的Core Data堆栈。单身人士提及“rootContext”,“mainContext”和创建新的临时背景mocs的方法。 多数民众赞成我是如何做到这一点,我的2C。 所以我可以得到类似于: NSManagedObjectContext * tempContext = [FooBarProject newContextWithConcurrencyType:NSPrivateConcurrencyType]; ..每当我需要一个新的临时背景在后台进程。 – oehman