8

我对 CoreData 比较陌生,我想知道我是否做对了。首先文档说:

“按照惯例,您从视图控制器获取上下文。但是,您必须适当地实现您的应用程序才能遵循这种模式。

当你实现一个与 Core Data 集成的视图控制器时,你可以添加一个 NSManagedObjectContext 属性。

当你创建一个视图控制器时,你将它应该使用的上下文传递给它。您传递现有的上下文,或者(在您希望新控制器管理一组离散的编辑的情况下)为它创建的新上下文。应用程序委托通常负责创建上下文以传递给显示的第一个视图控制器。”
https://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/stack.html

所以我要做的是为我的 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;
  1. 为每个视图控制器创建一个 NSManagedObjectContext 是一种好的做法,您将在其中对数据库进行一些更改?
    1.1。使用 [UIApplication sharedApplication] 从 appdelegate 获取持久的 NSPersistentStoreCoordinator 是一种有效的方法吗?
  2. 在主线程和任何其他线程之间共享持久存储协调器是安全的吗?

任何帮助将不胜感激 :)。

4

5 回答 5

3

我不同意这里的大多数答案。这对#1 来说还不错。事实上,在大多数情况下这样做可能是一种很好的做法。特别是如果你有不同的线程运行东西。它极大地简化了我的应用程序,以便在需要时创建 NSManagedObjectContexts,包括每个视图控制器。这也是 MagicalRecord 背后的人推荐的(这是我在大多数情况下使用 Core Data 的方法)。NSManagedObjectContext 创建对于 MR 人员来说并不是一个高开销的调用。无论如何,我都不是 CoreData 专家,但是按照 MagicalRecord 的人向我推荐的方式,我这样做的结果要好得多。

于 2013-12-20T19:32:47.303 回答
1

我只能为问题 #1 提供帮助。以下是 Apple 文档所说的将上下文传递给您的视图控制器时的含义的示例。在这种情况下,应用程序委托在应用程序委托创建上下文后将上下文传递给根视图控制器。

// 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;
}
于 2013-10-01T19:39:55.427 回答
0

这不是必需的,但它是一种强大的技术,可以在视图控制器中管理一组离散的编辑,该控制器将用于编辑项目,例如下面来自Apple 的 CoreDataBooks 示例的片段。您想要这样做的原因是您可以使用 Core Data 的所有功能来更新您的 UI,而无需撤消主上下文中的所有内容,如果用户决定取消,则可以简单地丢弃子上下文。NSManagedObjectContext也有可能通过's 的新automaticallyMergesChangesFromParent属性将父母的更改下推给孩子。

根视图控制器.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];
}
于 2019-03-09T15:55:24.020 回答
-1
  1. 不,创作不好NSManagedObjectContext不,为每个控制器您所需要的只是为每个线程拥有自己的上下文。所以这取决于你的逻辑。1.1。是的,这还不错。
  2. 是的,它是安全的。

在我的应用程序中,我使用带有 shared 的单例类NSPersistentStoreCoordinator。如果我需要创建新的上下文,我使用

self.context = [NSManagedObjectContext new];
self.context.persistentStoreCoordinator = [[SharedStorage sharedStorage] storeCoordinator];

这里有一个详细的代码片段。通常我使用的视图控制器NSManagedObjectContext有表视图,所以我使用NSFetchedResultsController. 我对所有这些控制器只使用一个共享上下文。

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

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

于 2013-10-01T18:56:25.203 回答
-1

坏:为每个要在数据库中进行一些更改的视图控制器创建 NSManagedObjectContexts 好:创建一个单独的 NSManagedObjectContext aka singleton,它将传递给那些想要在数据库中进行一些更改的视图控制器,这意味着就是这样,因为该应用程序基本上只有一个数据库,尽管您可以在一个应用程序中拥有多个数据库。示例1:假设您创建了一个基于Tab 的应用程序,那么窗口的rootViewController 将是UITabBarController,您可以从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.
}

还有很棒的 Core Data 库,又名 MagicalRecord,如果您想节省时间,可以在这里查看:https ://github.com/magicalpanda/MagicalRecord ,它真的很棒,但它不能替代 Core Data。还有一个如何在这里创建核心数据单例的示例:http: //steamheadstudio.pl/wordpress/core-data-singleton-with-sample-code/

于 2013-11-14T23:11:57.820 回答