I am trying to create a Core Data-based Mac OS X application. I've used Core Data on iOS, but things are a little different with AppKit. I am also using Xcode 4.1 on 10.7, and I know some Core Data things have changed on Lion. The only up-to-date reference from Apple is a recent WWDC session, which promises/suggests updated references on Apple.com, but most of the Core Data stuff is very out of date.
To start, I used Xcode to generate a Document-based project using Core Data. I hollowed out some of the Main Menu bits (deleted some menu items) and got rid of the NSWindow
object inside Main Menu.xib
, creating my own MyDocument.xib
with a NSWindow
(and sub-views) instead.
Questions:
I assume that a Persistent Store Controller always needs a persistent store, so if a new document is created, I'm just adding an in-memory store. When opening up from disk, I create it using the SQLite store. Is that correct?
I (ostensibly) do a store migration in
writeToURL:ofType:error:
if theurl
is different. But if I set a breakpoint inwriteToURL:ofType:error:
, and then hit Save, my breakpoint is not hit. Why not?If I choose "Revert to Saved", the application crashes -- hard. I have to force-quit it (and quit Xcode). Why?
(Very) old video tutorials suggest a way to easily bind data to a
UIView
like a table. Following along with Xcode is impossible since so much has changed. Any newer references out there for that?
Code:
MyDocument.h
:
#import <Cocoa/Cocoa.h>
@interface MyDocument : NSPersistentDocument
{
@private
NSManagedObjectModel* mom;
NSPersistentStoreCoordinator* psc;
NSManagedObjectContext* moc;
}
@end
MyDocument.m
:
#import "MyDocument.h"
@interface MyDocument ()
- (void)setUpManagedObjectModel;
- (void)setUpPersistentStoreCoordinator;
- (void)setUpManagedObjectContext;
- (BOOL)addPersistentStore:(NSString*)type url:(NSURL*)url error:(NSError**)outError;
@end
@implementation MyDocument
- (void)dealloc
{
[moc release];
[psc release];
[mom release];
[super dealloc];
}
- (id)init
{
self = [super init];
if (self)
{
[self setUpManagedObjectModel];
[self setUpPersistentStoreCoordinator];
[self setUpManagedObjectContext];
}
return self;
}
- (id)initWithType:(NSString *)typeName error:(NSError **)outError
{
self = [super initWithType:typeName error:outError];
if (self)
{
[self addPersistentStore:NSInMemoryStoreType url:nil error:outError];
}
return self;
}
- (BOOL)readFromURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError **)outError
{
return [self addPersistentStore:NSSQLiteStoreType url:url error:outError];
}
- (BOOL)writeToURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError **)outError
{
NSPersistentStore* currentStore = [[psc persistentStores] lastObject];
if (![[currentStore URL] isEqual:url])
{
NSPersistentStore* newStore = [psc migratePersistentStore:currentStore
toURL:url
options:nil
withType:typeName
error:outError];
if (!newStore)
{
return NO;
}
}
return [moc save:outError];
}
- (NSString *)windowNibName
{
// Override returning the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
return @"MyDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *)aController
{
[super windowControllerDidLoadNib:aController];
// Add any code here that needs to be executed once the windowController has loaded the document's window.
}
+ (BOOL)autosavesInPlace
{
return YES;
}
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
NSLog(@"menu item: %@", [item title]);
return YES;
}
#pragma mark Private Methods
- (void)setUpManagedObjectModel
{
NSURL* modelUrl = [[NSBundle mainBundle] URLForResource:@"MyDatabase" withExtension:@"momd"];
mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelUrl];
}
- (void)setUpPersistentStoreCoordinator
{
psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
}
- (void)setUpManagedObjectContext
{
moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:psc];
}
- (BOOL)addPersistentStore:(NSString*)type url:(NSURL*)url error:(NSError**)outError
{
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSPersistentStore* ps = [psc addPersistentStoreWithType:type
configuration:nil
URL:url
options:options
error:outError];
return (ps != nil);
}
@end