簡體   English   中英

如何正確管理每個視圖控制器中的NSManagedObjectContext?

[英]How to correctly manage the NSManagedObjectContext in each view controller?

我是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. 在主線程和任何其他線程之間共享持久性存儲協調器是安全的嗎?

任何幫助將不勝感激 :)。

我不同意這里的大多數答案。 對於#1來說還不錯。 實際上,在大多數情況下這樣做可能是個好習慣。 特別是如果您有不同的線程正在運行的東西。 它極大地簡化了我的應用程序,以便在需要時(包括每個視圖控制器)創建NSManagedObjectContexts。 MagicalRecord背后的人也建議這樣做(這是我在大多數情況下使用的核心數據)。 每個MR員工對NSManagedObjectContext的創建並不是一個高開銷的調用。 憑空想像力,我不是CoreData專家,但是按照MagicalRecord的建議,這樣做的結果要好得多。

我只能為問題#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;
}

並不是必須的,但這是一種強大的技術,可以在視圖控制器中管理一組離散的編輯內容,例如,如Apple的CoreDataBooks示例中的以下片段所示,該控件將用於編輯項目。 之所以要這樣做,是因為您可以使用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];
}
  1. 不,為每個控制器創建NSManagedObjectContext不好。 您需要做的是為每個線程擁有自己的上下文。 因此,這取決於您的邏輯。 1.1。 是的,還不錯。
  2. 是的,這很安全。

在我的應用程序中,我使用具有共享NSPersistentStoreCoordinator的單例類。 如果我需要創建新的上下文,請使用

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

這里有一些詳細的代碼片段。 通常,使用NSManagedObjectContext視圖控制器具有表視圖,因此我使用NSFetchedResultsController 對於所有這些控制器,我僅使用一個共享上下文。

注意1:有人說擁有單身是一個壞主意。

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

壞:在數據庫中為每個要進行一些更改的viewController創建NSManagedObjectContexts。好的:創建一個NSManagedObjectContext aka單例,將其傳遞給想要在數據庫中進行一些更改的視圖控制器,這意味着這是因為,盡管一個應用程序中可以有多個數據庫,但該應用程序基本上只有一個數據庫。 示例1:假設您創建了一個基於Tab的應用程序,則窗口的rootViewController將是UITabBarController,從根目錄中您可以獲取所有其他控制器! 在這里您可以將上下文傳遞給他們

- (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/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM