在哪里实施核心数据?

时间:2011-07-11 15:19:18

标签: iphone ios core-data nsmanagedobjectcontext

我对核心数据编程完全陌生。我只想找出实现核心数据代码的最佳位置。我已经完成了苹果教程Locations并且效果很好。现在我尝试将它转移到我当前的项目有点复杂。

Locations教程显示了一个RootViewController,包括一个以编程方式生成的tableView。我的项目基于tabView模板。它拥有一个MainWindow.xib,包括TabBarController,包括三个ViewController(MapView,ListView,SettingsView),其中每个视图都有自己的navigationController和xib文件。

第一个障碍是更改将使用xib为tableView运行的代码,而不是以编程方式创建它。我设法做到了,但仍有一个错误。我无法将appDelegate中的managedObjectContext连接到listViewController。我在这里从这个论坛尝试了这个问题的例子和建议。但它仍然无效。

在查看CoreDataBooks示例项目后,我发现核心数据代码也是在RootViewController中实现的。似乎在ListViewController中实现它是错误的方法。但我的项目中没有RootViewController。在AppDelegate中,我直接将tabBarController作为rootViewController传递。因此我不知道如何到达listViewController以设置上下文,就像在Locations示例中完成的那样。

由于MapView是第一个视图,我无法在appDelegate中设置上下文。在与managedObjectContext进行了长时间的努力之后,我想知道发明一个RootViewController以便能够在那里放置额外的代码会更好。所有三个视图都应该可以访问模型,而且看起来RootViewController是正确的位置。

但是我如何将它与tabBarController相结合,后者还包含三个基于xib文件的viewControllers?有人可以推荐我的示例或tutrials,包括基于标签栏应用程序的核心数据吗?

4 个答案:

答案 0 :(得分:3)

请阅读Marcus Zarra撰写的以下文章:Passing around a NSManagedObjectContext on iOS。这应该会让你知道如何解决你的问题。

通常,您应该向所有ViewControllers添加NSManagedObjectContext属性,并在通过pushViewController:animated:将它们添加到视图堆栈之前传递上下文。您不应该从应用代理中获取上下文。

如果将单个NSManagedObject传递给ViewController,例如为了呈现一种详细视图,您可以从该对象访问上下文,因为每个NSManagedObject都知道它所处的NSManagedObjectContext。

如果您是注册的iOS开发人员,我还会推荐WWDC 2010和2011视频。有一些关于掌握核心数据的会议。

答案 1 :(得分:1)

好的,现在我有了正确的解决方案。需要一段时间才能理解,但现在它可以使用从应用程序委托到视图控制器(listViewController)的依赖注入。

我的问题是我不知道如何引用我的视图控制器,因为它们嵌套在专用的navControllers和一个tabBarController中。

在阅读了很多帖子后,我知道我必须在appDelegate.h中声明我的视图控制器并在appDelegate.m中合成它们,之后将它们连接到IB中的适当项目。这是快速完成的理解后容易: - )

不需要rootViewController。

MyAppDelegate.h:

#import <UIKit/UIKit.h>
#import "ListViewController.h"

@interface MyAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {

    UIWindow *window;
    UITabBarController *tabBarController;
    IBOutlet ListViewController *listViewController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
@property (nonatomic, retain) IBOutlet ListViewController *listViewController;

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

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

@end

MyAppDelegate.m:

#import "MyAppDelegate.h"
#import "ListViewController.h"

@implementation MyAppDelegate

@synthesize window=_window;

@synthesize tabBarController=_tabBarController;

@synthesize managedObjectContext=__managedObjectContext;

@synthesize managedObjectModel=__managedObjectModel;

@synthesize persistentStoreCoordinator=__persistentStoreCoordinator;

@synthesize listViewController;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    NSManagedObjectContext *context = [self managedObjectContext];

    if (!context) {
        // Handle the error.
    }
    // Pass the managed object context to the view controller.
    listViewController.managedObjectContext = context;

    // Override point for customization after application launch.
    // Add the tab bar controller's current view as a subview of the window
    self.window.rootViewController = self.tabBarController;

    [self.window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];  
    return YES;
}

...

ListViewController.h

#import <CoreLocation/CoreLocation.h>


@interface ListViewController : UITableViewController <CLLocationManagerDelegate> {

    UINavigationController *navController;
    NSManagedObjectContext *managedObjectContext;
}

@property (nonatomic, retain) IBOutlet UINavigationController *navController;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

-(NSManagedObjectContext *)managedObjectContext;

@end

ListViewController.m

#import "MyAppDelegate.h"
#import "ListViewController.h"


@implementation ListViewController

@synthesize navController;
@synthesize managedObjectContext;

- (void)viewDidLoad {

    [super viewDidLoad];

    NSLog(@"managedObjectContext: %@",[self managedObjectContext]);

    NSError *error = nil;
    if (![managedObjectContext save:&error]) {
        NSLog(@"error: %@",[self managedObjectContext]);
        return;
    }

...

答案 2 :(得分:0)

我前段时间编写过这样的应用程序。我解决它的方式是我创建了一个单例,它具有persistentStoreCoordinator属性,就像Apple文档中的属性一样,用于保存对数据库的访问(所以我不必每次都写它)。然后在每个标签栏视图控制器中,我都启动了自己的NSManagedObjectContext。

NSPersistentStoreCoordinator *coordinator = [[Singleton sharedSingleton] persistentStoreCoordinator];
        if (coordinator != nil) {
            _managedObjectContext = [[NSManagedObjectContext alloc] init];
            [_managedObjectContext setPersistentStoreCoordinator: coordinator];
        }

这样,如果你理解我的意思,每个控制器都会使用它自己的上下文来接近数据库。

请注意,如果您的任何视图控制器都有详细视图控制器,请采用标准方法将托管对象上下文传递给它,如示例代码(Books,Locations,Recipes)。

答案 3 :(得分:0)

我刚刚解决了这个问题。我错过了appDelegate中必要的一些方法。如果我将以下代码放入我的ListViewController的viewDidLoad

,它现在有效
if (managedObjectContext == nil) { 
    NSLog(@"managedObjectContext is nil");
    managedObjectContext = [(IntraAppAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}

关于正确的MVC模式规则是否正常?在我的例子中,ViewController现在从appDelegate获取上下文。

尝试在appDelegate中设置上下文时会抛出错误:

 NSManagedObjectContext *context = [self managedObjectContext];

    if (!context) {
        // Handle the error.
    }
    // Pass the managed object context to the view controller.

    self.tabBarController.listViewController.navController.managedObjectContext = context;
    self.window.rootViewController = self.tabBarController;

如何收集由tabBarController控制的其他viewControllers的引用,并且不是app启动后的topView / superView?第一个视图是MapView。我必须在appDelegate中实例化或声明listViewController吗?如何编码它引用tabBarController控制的listViewController?