【问题标题】:'+entityForName: nil is not a legal NSManagedObjectContext'+entityForName: nil 不是合法的 NSManagedObjectContext
【发布时间】:2013-08-28 03:17:50
【问题描述】:

当我尝试将数据从 Core Data 加载到 Table View 控制器时出现错误。我相信这是由于 managedObject 没有被正确传递。

但我相信我是在对 didFinishLaunchingWithOptions 下的 AppDelegate.m 中的代码进行一些研究后才这样做的。

错误

*** 由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“+entityForName:nil 不是搜索实体名称“Club”的合法 NSManagedObjectContext 参数

MLVAPPDelegate.h

#import <UIKit/UIKit.h>

@interface MLVAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

@end

MLVAppDelegate.m

#import "MLVAppDelegate.h"
#import "MLVSyncEngine.h"
#import "Club.h"
#import "IronSet.h"
#import "MLVClubSelectionViewController.h"


@implementation MLVAppDelegate

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UITabBarController *tabController = (UITabBarController *)self.window.rootViewController;

    UINavigationController *navigationController = (UINavigationController *)[[tabController viewControllers] objectAtIndex:0];
    MLVClubSelectionViewController *controller = (MLVClubSelectionViewController *)[[navigationController viewControllers] objectAtIndex:0];
    controller.managedObjectContext = self.managedObjectContext;

    [[MLVSyncEngine sharedEngine] registerNSManagedObjectClassToSync:[Club class]];

    [[MLVSyncEngine sharedEngine] registerNSManagedObjectClassToSync:[IronSet class]];

    return YES;
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [[MLVSyncEngine sharedEngine] startSync];
}

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

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_managedObjectContext performBlockAndWait:^{
            [_managedObjectContext setPersistentStoreCoordinator:coordinator];
        }];
    }
    return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"GolfCalculator" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

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

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {

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

    return _persistentStoreCoordinator;
}

#pragma mark - Application's Documents directory

// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

@end

MLVClubSelectionViewController.h

#import <UIKit/UIKit.h>

@interface MLVClubSelectionViewController : UITableViewController

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;

@end

MLVClubSelectionViewController.m

#import "MLVClubSelectionViewController.h"
#import "Club.h"
#import "IronSet.h"
#import "MLVCoreDataController.h"

@interface MLVClubSelectionViewController ()

@end

@implementation MLVClubSelectionViewController
@synthesize managedObjectContext;
@synthesize fetchedResultsController = _fetchedResultsController;

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }

    self.title = @"Club Selection";
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
    // Return the number of sections.
    return 0;
}

- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section {
    id  sectionInfo =
    [[_fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    Club *info = [_fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = info.fullTitle;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@",
                                 info.model, info.level];
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell =
    [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    // Set up the cell...
    [self configureCell:cell atIndexPath:indexPath];

    return cell;
}


#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

}

#pragma mark - Fetched Results 
- (NSFetchedResultsController *)fetchedResultsController {

    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"Club" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                              initWithKey:@"make" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:managedObjectContext sectionNameKeyPath:nil
                                                   cacheName:@"Root"];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray
                                               arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray
                                               arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];
}
- (void)viewDidUnload {
    self.fetchedResultsController = nil;
}

@end

【问题讨论】:

  • managedObjectController 如何在您的应用委托上设置?这必须在您在MLVClubSelectionViewController 上设置managedObjectController 之前发生。此外,子类化UINavigationController 是不寻常的——您可能无需这样做就可以构建您的应用程序。
  • 我从另一个 SO 问题的研究中做了子类,他们建议将它用于选项卡控制器。
  • 我已经用设置 managedObjectController 的完整 AppDelegate 对其进行了更新。
  • 你已经实现了masterManagedObjectContext,但从不从任何地方调用它。
  • 我想这是我正在寻找的部分。我虽然我所拥有的足以让它显示在表格视图中。我应该添加什么?

标签: iphone ios cocoa-touch core-data


【解决方案1】:

您已经实现了方法masterManagedObjectContext,但您从未调用它。您正在分配 managedObjectContext 属性的值(与所有对象属性一样,将初始化为 nil),作为传递给控制器​​的上下文。

您可以执行以下操作之一:

  1. masterManagedObjectContext 重命名为managedObjectContext,这将提供managedObjectContext 访问器的延迟加载实现(意味着self.managedObjectContext 不应再评估为nil
  2. 您也可以按如下方式实现managedObjectContext

    - (NSManagedObjectContext *)managedObjectContext {
        return [self masterManagedObjectContext];
    }
    
  3. 从应用程序委托中删除 managedObjectContext 属性并仅使用 masterManagedObjectContext 方法。这还需要显式定义_managedObjectContext 实例变量。

【讨论】:

  • 所以我进行了第一步,并在 App Delegate 中将 masterManagedObjectContext 重命名为 managedObjectContext,现在错误消失了。但是表格视图控制器仍然是空白的。
  • 您在调试时发现了什么?另外,你还在numberOfSectionsInTableView:中返回0吗?这将确保一个空白的表格视图:)
  • 另外 - 我创建了一个聊天频道 chat.stackoverflow.com/rooms/36417/… 随时加入我会尽力帮助你
猜你喜欢
  • 1970-01-01
  • 2012-07-20
  • 1970-01-01
  • 2015-07-06
  • 2014-09-28
  • 2013-12-26
  • 2014-02-23
  • 1970-01-01
相关资源
最近更新 更多