我对核心数据编程完全陌生。我只想找出实现核心数据代码的最佳位置。我已经完成了苹果教程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,包括基于标签栏应用程序的核心数据吗?
答案 0 :(得分:3)
请阅读Marcus Zarra撰写的以下文章:Passing around a NSManagedObjectContext on iOS。这应该会让你知道如何解决你的问题。
通常,您应该向所有ViewControllers添加NSManagedObjectContext属性,并在通过pushViewController:animated:
将它们添加到视图堆栈之前传递上下文。您不应该从应用代理中获取上下文。
如果将单个NSManagedObject传递给ViewController,例如为了呈现一种详细视图,您可以从该对象访问上下文,因为每个NSManagedObject都知道它所处的NSManagedObjectContext。
如果您是注册的iOS开发人员,我还会推荐WWDC 2010和2011视频。有一些关于掌握核心数据的会议。
答案 1 :(得分:1)
我的问题是我不知道如何引用我的视图控制器,因为它们嵌套在专用的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?