managedObjectContext无法识别的选择器发送到实例

时间:2013-12-27 06:07:42

标签: ios core-data nsmanagedobjectcontext

我正在学习开发iOS应用程序的教程。我正在使用核心数据。该应用的第一个视图是RootViewController。所有Core Data堆栈都在AppDelegate文件上。这是来自AppDelegate.m的代码的一部分,用于调用RootViewController文件:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // Fetch the data to see if we ought to pre-populate
  NSError *error = nil;
  if (![[self fetchedResultsController] performFetch:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
  }

  [self loadFavoriteThingsData];        

  RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
  [rootViewController setManagedObjectContext:[self managedObjectContext]];       

  [window addSubview:[navigationController view]];
  [window makeKeyAndVisible];
  return YES;
}

现在,在应用的另一部分,我需要打开一个新视图控制器,它与RootViewController重复,称为DoneViewController,但使用其他NSPredicate来显示其他核心数据对象。

RootViewController中有一个按钮可以打开MenuViewController文件,我尝试使用以下方法打开DoneViewController

- (IBAction)doneToDoaction:(id)sender {
    DoneViewController *viewController = [[DoneViewController alloc] init];

    [self presentViewController:viewController animated:YES completion:nil];
}

但是引发了一个例外:

[MenuViewController managedObjectContext]: unrecognized selector sent to instance 0x145a0c00
2013-12-26 22:58:23.688  *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MenuViewController managedObjectContext]: unrecognized selector sent to instance

我想我必须将managedObjectContextRootViewController传递到MenuViewController,然后从MenuViewController传递到DoneViewController,但我不知道如何做到这一点。

2 个答案:

答案 0 :(得分:8)

这是因为您没有使用NSObject类。为此,你必须在AppDelegate.h中实现NSObject。就像这个..

@interface AppDelegate : UIResponder <UIApplicationDelegate,NSObject>{
    NSManagedObjectModel *managedObjectModel;
    NSManagedObjectContext *managedObjectContext;
    NSPersistentStoreCoordinator *persistentStoreCoordinator;
}

并添加属性。

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

- (NSString *)applicationDocumentsDirectory;

还在AppDelegate.m文件中添加代码......

 - (NSManagedObjectContext *) managedObjectContext {
    if (managedObjectContext != nil) {
        return managedObjectContext;
    }
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }

    return managedObjectContext;
}

 - (NSManagedObjectModel *)managedObjectModel {
    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
    managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil] ;

    return managedObjectModel;
}

 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator

 {

    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }
    NSURL *storeUrl = [NSURL fileURLWithPath: [[self  applicationDocumentsDirectory]
                                               stringByAppendingPathComponent: @"<Project Name>.sqlite"]];
    NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
                                  initWithManagedObjectModel:[self managedObjectModel]];
        if(![persistentStoreCoordinator      addPersistentStoreWithType:NSSQLiteStoreType configuration:nil   URL:storeUrl options:nil error:&error]) 
  {
        /*Error for store creation should be handled in here*/
  }

    return persistentStoreCoordinator;
}
- (NSString *)applicationDocumentsDirectory {
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}

这对我100%有效。希望这对你有用。

答案 1 :(得分:0)

很少有解决方案可以做你想做的事。

第一种是从@Gyanendra评论的应用程序委托中公开上下文。第二种是将上下文从控制器传递给控制器​​。如需进一步参考,我建议您阅读Marcus Zarra撰写的PASSING AROUND A NSMANAGEDOBJECTCONTEXT ON IOS

无论如何,我更喜欢第二种解决方案。绕过上下文或抓取NSManagedObject的实例。基于后者,每个NSManagedObjectInstance都有对已注册的上下文的引用。

[managedObjectInstance managedObjectContext];

这些解决方案可防止严格的应用程序,并避免污染应用程序委托。

在您的情况下,您可以采用这种方法。从RootViewController开始将上下文传递给MenuViewController,然后从后者传递给DoneViewController。怎么样?

足够简单。只需公开您感兴趣的控制器等属性(在这种情况下为MenuViewControllerDoneViewController)。

@property (nonatomic, strong) NSManagedObjectContext* mainContext;

可以设置为

// from RootViewController
menuViewController.mainContext = [self managedObjectContext];