Мы уже рассмотрели как настраивается Core Data стек. К примеру вы всегда имеете managed object context и persistent store. Разумеется у вас есть модель данных (которая приблизительно совпадает со схемой БД). Также у вас есть SQLite-файл содержащий данные persistent store. Core Data можно настроить на работу не только с SQLite.
Фреймворки Cocoa для Mac OS и Cocoa Touch для iOS эволюционировали из NeXTSTEP и OpenStep разработанные компанией NeXT (куплена Apple в 1995 году). Также они эволюционировали из раних фреймворков и сред разработки, которые разрабатываются в Apple с 1984 года.
Можно предоставить Core Data stack (data model, managed object context, и persistent store) для отдельного документа. Это позволит работать с данными на уровне документов. Если один и тот же документ открыть в двух окнах, то каждое окно будет иметь собственный Core Data stack.
Есть возможность обеспечить версионность документов.
Library/shoebox приложения вместо документов используют persistent store, который поддерживается самим приложением. Например, в iPhoto или iCal ваши данные хранятся в единственном файле, который сокрыт в папке Library/Application Support/.
Одну и ту же модель данных можно использовать как на Mac OS так и на iOS.
Создание Mac OS Library/Shoebox-Based приложения
Создадим новый Xcode-проект:
В Objective-C для расширения функциональности классов часто используются делегаты. В других языках применяю наследование. В данном случае при создании нового проекта создался делегат AppDelegate.
#import <Cocoa/Cocoa.h> @interface AppDelegate : NSObject <NSApplicationDelegate> @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @end
Метод windowWillReturnUndoManager: возвращает undo manager для managed object context.
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window { // Returns the NSUndoManager for the application. In this case, the manager returned is that of the managed object context for the application. return [[self managedObjectContext] undoManager]; }
Таким образом Core Data управляет операциями undo и redo в окне отображающем данные.
Метод saveAction: коммитит изменения и сохраняет данные в managed object context.
- (IBAction)saveAction:(id)sender { // Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user. if (![[self managedObjectContext] commitEditing]) { NSLog(@"%@:%@ unable to commit editing before saving", [self class], NSStringFromSelector(_cmd)); } NSError *error = nil; if ([[self managedObjectContext] hasChanges] && ![[self managedObjectContext] save:&error]) { [[NSApplication sharedApplication] presentError:error]; } }
Создание iOS Library/Shoebox-Based приложения
Создадим Master-Detail приложение.Базовая структура приложения аналогична той, что мы видели под Mac OS. Делегат приложения AppDelegate унаследован от класса UIResponder и принимает протокол UIApplicationDelegate.
#import <UIKit/UIKit.h> #import <CoreData/CoreData.h> @interface AppDelegate : 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
Тут вместо saveAction: указан saveContext. И добавлен метод доступа applicationDocumentsDirectory.
Создание Mac OS Document-Based приложения
Создадим новый Xcode-проект:В созданном проекте файлы Document.h и Document.m представляют собой класс проекта. Данный унаследован от NSPersistentDocument.
В файле Document.xcdatamodeld содержится пустая модель данных.
По умолчанию на Mac OS дается три типа документов: бинарный, XML и SQLite.
Если вы собираетесь использовать только SQLite, то остальные два можно удалить. Это упростит работу с приложением т.к. пользователю при сохранении документа не придется выбирать его тип.
Класс документа должен имплементировать Core Data stack.
#import <Cocoa/Cocoa.h> @interface MyDocument : NSPersistentDocument { NSManagedObject *customer; } - (NSManagedObject *)customer; - (void)setCustomer:(NSManagedObject *)aCustomer; @end
#import “MyDocument.h” @implementation MyDocument
#pragma mark - Application life cycle
- (id)init { self = [super init]; if (self) { // Add your subclass-specific initialization here. // If an error occurs here, return nil. } return self; }
- (id)initWithType:(NSString *)type error:(NSError **)error { self = [super initWithType:type error:error]; if (self != nil) { NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; [self setCustomer:[NSEntityDescription insertNewObjectForEntityForName:@”Customer” inManagedObjectContext:managedObjectContext]]; // To avoid undo registration for this insertion, removeAllActions on the // undoManager. // First call processPendingChanges on the managed object context to force // the undo registration // for this insertion, then call removeAllActions. [managedObjectContext processPendingChanges]; [[managedObjectContext undoManager] removeAllActions]; [self updateChangeCount:NSChangeCleared]; } return self; }
#pragma mark - View/window life cycle
- (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. }
#pragma mark - Autosave and versions
+ (BOOL)autosavesInPlace { return YES; }
#pragma mark - Core Data stack
- (NSManagedObject *)customer { if (customer != nil) { return customer; } NSManagedObjectContext *moc = [self managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSError *fetchError = nil; NSArray *fetchResults; @try { NSEntityDescription *entity = [NSEntityDescription entityForName:@”Customer” inManagedObjectContext:moc]; [fetchRequest setEntity:entity]; fetchResults = [moc executeFetchRequest:fetchRequest error:&fetchError]; } @finally { //[fetchRequest release]; } if ((fetchResults != nil) && ([fetchResults count] == 1) && (fetchError == nil)) { [self setCustomer:[fetchResults objectAtIndex:0]]; return customer; } if (fetchError != nil) { [self presentError:fetchError]; } else { // should present custom error message... } return nil; }
- (void)setCustomer:(NSManagedObject *)aCustomer { if (customer != aCustomer) { customer = aCustomer; } } @end