-[UITableViewController setManagedObjectContext:]: 无法识别的选择器发送到实例0x7490da0

3

我知道错误发生在这一行,因为如果将此行注释掉,应用程序就可以正常运行:

controller.managedObjectContext = self.managedObjectContext;

错误信息为:

应用程序因未捕获的异常而终止,原因是:“- [UITableViewController setManagedObjectContext:]:向实例0x7490da0发送无法识别的选择器”

fibroMappAppDelegate.h文件

//
//  fibroMappAppDelegate.h
//  fibromapp
//
//  Created by jamie mcallister on 09/08/2013.
//  Copyright (c) 2013 Jamie McAllister. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface fibroMappAppDelegate : 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;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

@end

并且是 fibroMappAppDelegate.m 文件

//
//  fibroMappAppDelegate.m
//  fibromapp
//
//  Created by jamie mcallister on 09/08/2013.
//  Copyright (c) 2013 Jamie McAllister. All rights reserved.
//

#import "fibroMappAppDelegate.h"

#import "fibroMappMasterViewController.h"

@implementation fibroMappAppDelegate

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

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
   fibroMappMasterViewController *controller = (fibroMappMasterViewController *)navigationController.topViewController;
    controller.managedObjectContext = self.managedObjectContext;
    return YES;
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Saves changes in the application's managed object context before the application terminates.
    [self saveContext];
}

- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![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();
        } 
    }
}

#pragma mark - Core Data stack

// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
- (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:@"fibromapp" 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:@"fibromapp.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;
}

#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

fibroMappMasterViewController的代码中有managedContext吗? - Larme
从错误信息来看,控制器是UITableviewController,而不是fibroMappMasterViewController。此外,如果您“完全是iOS新手”,那么从使用核心数据的项目开始可能不是最好的选择 - 这不是初学者级别的API。 - rdelmar
一个小的侧面说明。Objective-C编码规范要求类名的首字母大写。你不会得到编译错误,但强烈建议这样做。 - Marcus S. Zarra
@rdelmar,很遗憾,对我来说轻松起步不是一个选项,因为我需要制作这个应用程序来产生一些收入(有人要求我制作它,我将获得所有利润的50%)。 - Jamie McAllister
@MarcusS.Zarra 是的,我是在上大学学习编程后才开始开发这个应用程序的。 - Jamie McAllister
3个回答

3
这意味着当您执行以下操作时:
controller.managedObjectContext = self.managedObjectContext;

controller 没有 managedObjectContext 属性,因此无法将任何内容分配给它。您没有发布 controller 的代码,因此我不知道它的确切外观,但错误消息表明它是一个 UITableViewController。如果您想以正确的方式解决此问题,您需要为 controller 提供一个 managedObjectContext 属性,以便您可以使此分配工作。


感谢Tom和Marcus,我通过创建一个UITableView的子类并添加属性,然后将其分配给我的第一个视图控制器来解决了这个错误。 - Jamie McAllister

2

您所需要做的就是删除这一行:

controller.managedObjectContext = self.managedObjectContext;

每当您需要在视图中使用托管对象上下文时,请使用以下代码:

[(fibroMappAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

那么你的意思是我会使用context = [(fibroMappAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];吗? - Jamie McAllister
3
那是一个不太理想的模式。你应该使用依赖注入(dependency injection)而不是总是去应用程序委托(app delegate)获取MOC(managed object context)。更好的做法是实际解决代码错误,而不是这样做。 - Marcus S. Zarra
1
马库斯刚才说你一直在试图第一次就做对,而且你应该修复你正在做的事情,而不是遵循这个建议。 - Tom Harrington
@JamieMcAllister 为什么你取消了我的答案? - Abdullah Shafique
1
因为这不是他问题的解决方案。解决方案是子类化UITableViewController并添加属性,以便他可以正确进行依赖注入。 - Marcus S. Zarra
显示剩余2条评论

2
该错误表明您正在使用非子类化的UITableViewController,并且认为您正在使用具有名为“managedObjectContext”的属性的子类。请检查您的storyboard、xib或代码,看看这是在哪里发生的。
由于您正在尝试使用依赖注入(非常好的事情),因此我建议检查您创建控制器的位置,并更改它,使其使用具有正确属性的UITableViewController的子类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接