Ios 如何在每个视图控制器中正确管理NSManagedObjectContext?

Ios 如何在每个视图控制器中正确管理NSManagedObjectContext?,ios,objective-c,core-data,Ios,Objective C,Core Data,我对CoreData比较陌生,我想知道我做的事情是否正确。首先,文件说明: 按照惯例,您可以从视图控制器获取上下文。不过,您必须适当地实现应用程序,才能遵循此模式 实现与核心数据集成的视图控制器时,可以添加NSManagedObjectContext属性。 创建视图控制器时,将传递它应该使用的上下文。传递现有上下文,或(在希望新控制器管理离散编辑集的情况下)为其创建的新上下文。应用程序委托通常负责创建一个上下文以传递给显示的第一个视图控制器。“ 因此,我要做的是为我的NSManagedObje

我对CoreData比较陌生,我想知道我做的事情是否正确。首先,文件说明:

按照惯例,您可以从视图控制器获取上下文。不过,您必须适当地实现应用程序,才能遵循此模式

实现与核心数据集成的视图控制器时,可以添加NSManagedObjectContext属性。

创建视图控制器时,将传递它应该使用的上下文。传递现有上下文,或(在希望新控制器管理离散编辑集的情况下)为其创建的新上下文。应用程序委托通常负责创建一个上下文以传递给显示的第一个视图控制器。“

因此,我要做的是为我的NSManagedObjectContext创建一个属性:

MyViewController.H
@interface MyViewController : ViewController
{
    NSManagedObjectContext *moc;
}

@property (nonatomic, retain) NSManagedObjectContext *moc;

@end

 MyViewController.m
 @implementation MyViewController
 @synthesize moc=moc;
1.-任何我想对数据库做一些更改的地方,我都会这样做。

MainNexarAppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];

self.moc = [[NSManagedObjectContext alloc] init];
self.moc.persistentStoreCoordinator = [appDelegate persistentStoreCoordinator];
/*code**/
[self.moc save:&error];
2-。如果我要在不同的线程中工作,我有自己的自定义方法,可以使用NSPrivateQueueConcurrencyType创建NSManagedObjectContext,以便可以在专用队列中管理它:

   //Myclass NSObject<br>

 -(NSManagedObjectContext *)createManagedObjectContext{

    MainNexarAppDelegate *appDelegate =
    [[UIApplication sharedApplication] delegate];

    NSPersistentStoreCoordinator *coordinator = [appDelegate persistentStoreCoordinator];
    if (coordinator != nil) {
        __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return __managedObjectContext;  
}
//__managedObjectContext is my property from the .h file 
//@property (readonly,strong,nonatomic)  NSManagedObjectContext* managedObjectContext;
//Myclass NSObject
-(NSManagedObjectContext*)createManagedObjectContext{ MainNexarAppDelegate*appDelegate= [[UIApplication sharedApplication]委托]; NSPersistentStoreCoordinator*coordinator=[appDelegate persistentStoreCoordinator]; if(协调器!=nil){ __managedObjectContext=[[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [\uu managedObjectContext setPersistentStoreCoordinator:coordinator]; } 返回uu managedObjectContext; } //__managedObjectContext是.h文件中的我的属性 //@属性(只读、强、非原子)NSManagedObjectContext*managedObjectContext;
  • 为每个视图控制器创建NSManagedObjectContext是一种好的做法,您将在其中对数据库进行一些更改吗?
    1.1. 使用[UIApplication sharedApplication]从appdelegate获取持久的NSPersistentStoreCoordinator是一种有效的方法吗
  • 在主线程和任何其他线程之间共享持久存储协调器是否安全 任何帮助都将不胜感激:)

  • 不,为每个对象创建
    NSManagedObjectContext
    是不好的 控制器。您所需要的只是为每个线程提供自己的上下文。所以 这取决于你的逻辑。 1.1. 是的,还不错
  • 是的,它是安全的
  • 在我的应用程序中,我使用带有共享
    NSPersistentStoreCoordinator
    的单例类。如果我需要创建新的上下文,我使用

    self.context = [NSManagedObjectContext new];
    self.context.persistentStoreCoordinator = [[SharedStorage sharedStorage] storeCoordinator];
    
    有点详细的代码片段。通常使用
    NSManagedObjectContext
    的视图控制器都有表视图,因此我使用
    NSFetchedResultsController
    。对于所有这些控制器,我只使用一个共享上下文

    注1:有人说单身是个坏主意


    注意2:不要忘记,您需要通过
    save
    merge
    方法同步所有上下文

    我只能为问题1提供帮助。下面是一个苹果文档的例子,当他们说将上下文传递给视图控制器时,他们的意思是什么。在这种情况下,在应用程序委托创建上下文后,应用程序委托将上下文传递给根视图控制器

    // in AppDelegate.m (using storyboard)
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        // Override point for customization after application launch.
    
        // let's assume that your MyViewController is the root view controller; grab a reference to the root view controller
        MyViewController *rootViewController = (MyViewController *)self.window.rootViewController;
    
        // initialize the Core Data stack...
    
        rootViewController.moc = ... // pass the context to your view controller
    
        return YES;
    }
    

    错误:在数据库中为每个要进行某些更改的viewController创建NSManagedObjectContext 好:创建一个NSManagedObjectContext,也称为singleton,它将被传递到那些 要在数据库中进行某些更改的视图控制器, 这意味着,虽然一个应用程序中可以有多个数据库,但该应用程序基本上只有一个数据库。 例1: 假设您创建了一个基于选项卡的应用程序,那么窗口的rootViewController将是uitabarcontroller,从root用户可以获得所有其他控制器!在这里,您可以向他们传递上下文

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        /* 
            MUNSharedDatabaseController is the singleton
         */
        UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
        UIViewController *firstViewController = tabBarController.viewControllers[0];
        firstViewController.managedObjectContext = [[MUNSharedDatabaseController sharedDatabaseController] managedObjectContext];
        UIViewController *secondViewController = tabBarController.viewControllers[1];
        secondVC.managedObjectContext = [[MUNSharedDatabaseController sharedDatabaseController] managedObjectContext];
        // otherStuff, or etc.
    }
    
    还有一个很棒的核心数据库,又名MagicalRecord 您可以在这里查看: 如果你想节省时间,它真的很棒,但它不是核心数据的替代品。
    这里还有一个如何创建核心数据单例的示例:

    我不同意这里的大多数答案。这对我来说并不坏。事实上,在大多数情况下这样做可能是一种好的做法。特别是如果你有不同的线程运行的东西。它大大简化了我的应用程序,可以在需要时创建NSManagedObjectContext,包括每个视图控制器。这也是MagicalRecord背后的人推荐的(在大多数情况下,我使用它来利用核心数据)。NSManagedObjectContext创建对于MR来说不是一个高开销的调用。我并不是一位CoreData专家,但我通过这种方式获得了更好的结果,正如MagicalRecord的伙计们向我推荐的那样。

    这并不是必需的,但它是一种强大的技术,可以在视图控制器中管理一组离散的编辑,这些编辑将用于编辑项目,例如下面的代码段。您希望这样做的原因是,您可以使用Core Data的所有功能来更新UI,而不必撤消主上下文中的所有内容。如果用户决定取消,则可以简单地放弃子上下文。还可以通过
    NSManagedObjectContext
    的新
    automaticallyMergesChangesFromParent
    属性将父项更改下推到子项

    RootViewController.m

    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    
        if ([[segue identifier] isEqualToString:@"AddBook"]) {
    
            /*
             The destination view controller for this segue is an AddViewController to manage addition of the book.
             This block creates a new managed object context as a child of the root view controller's context. It then creates a new book using the child context. This means that changes made to the book remain discrete from the application's managed object context until the book's context is saved.
              The root view controller sets itself as the delegate of the add controller so that it can be informed when the user has completed the add operation -- either saving or canceling (see addViewController:didFinishWithSave:).
             IMPORTANT: It's not necessary to use a second context for this. You could just use the existing context, which would simplify some of the code -- you wouldn't need to perform two saves, for example. This implementation, though, illustrates a pattern that may sometimes be useful (where you want to maintain a separate set of edits).
             */
    
            UINavigationController *navController = (UINavigationController *)[segue destinationViewController];
            AddViewController *addViewController = (AddViewController *)[navController topViewController];
            addViewController.delegate = self;
    
            // Create a new managed object context for the new book; set its parent to the fetched results controller's context.
            NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
            [addingContext setParentContext:[self.fetchedResultsController managedObjectContext]];
    
            Book *newBook = (Book *)[NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:addingContext];
            addViewController.book = newBook;
            addViewController.managedObjectContext = addingContext;
        }
    
        else if ([[segue identifier] isEqualToString:@"ShowSelectedBook"]) {
    
            NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
            Book *selectedBook = (Book *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
    
            // Pass the selected book to the new view controller.
            DetailViewController *detailViewController = (DetailViewController *)[segue destinationViewController];
            detailViewController.book = selectedBook;
        }    
    }
    
    #pragma mark - Add controller delegate
    
    /*
     Add controller's delegate method; informs the delegate that the add operation has completed, and indicates whether the user saved the new book.
     */
    - (void)addViewController:(AddViewController *)controller didFinishWithSave:(BOOL)save {
    
        if (save) {
            /*
             The new book is associated with the add controller's managed object context.
             This means that any edits that are made don't affect the application's main managed object context -- it's a way of keeping disjoint edits in a separate scratchpad. Saving changes to that context, though, only push changes to the fetched results controller's context. To save the changes to the persistent store, you have to save the fetch results controller's context as well.
             */        
            NSError *error;
            NSManagedObjectContext *addingManagedObjectContext = [controller managedObjectContext];
            if (![addingManagedObjectContext 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.
                 */
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
    
            if (![[self.fetchedResultsController 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. 
                 */
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }
    
        // Dismiss the modal view to return to the main list
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    

    MagicalRecord为几乎所有内容创建了一个新的上下文(有点夸张)。据MagicalRecord背后的人说,created NSMAnagedObjectContexts是一个低开销的调用,在需要时创建一个这样的调用并没有坏处。根据应用程序逻辑,为每个视图控制器创建一个视图控制器也不错。我正在使用MagicalRecord a