Core Data происходит от Enterprise Objects Framework (EOF) - разработки NeXT как части WebObjects в 1990-х. В 1996 после того как Apple купила NeXT, EOF трансформируется в Core Data framework и выпускается в составе Mac OS X 10.4 (Tiger) и позднее iOS.
Главная цель скомбинировать ООП и РСУБД.
Объектно-ориентированные базы данных (еще их называют объектые базы данных) были созданы в 1980-х годах.
Core Data хранит данные используя persistence store:
В качестве data management tool используется Core Data model editor (файлы с расширением .xcdatamodeld) в Xcode.
- SQLite на Mac или iOS,
- XML только на Mac.
В качестве data management tool используется Core Data model editor (файлы с расширением .xcdatamodeld) в Xcode.
Xcode автоматически сгенерирует код для сущности Place:
// // Place.h //
#import <Foundation/Foundation.h> #import <CoreData/CoreData.h> @interface Place : NSManagedObject @property (nonatomic, retain) NSString * address; @property (nonatomic, retain) NSSet *event; @end @interface Place (CoreDataGeneratedAccessors) - (void)addEventObject:(NSManagedObject *)value; - (void)removeEventObject:(NSManagedObject *)value; - (void)addEvent:(NSSet *)values; - (void)removeEvent:(NSSet *)values; @end
// // Place.m // #import “Place.h” @implementation Place @dynamic address; @dynamic event; @end
Обратите внимание, что класс унаследован от NSManagedObject. Вместо @synthesize используется @dynamic. Managed object - это объект созданный из сущности модели данных.
SQLite рассчитан на одного пользователя. Он определенно может использоваться в многопользовательской среде, но сегодня в основном используется на одного пользователя.
Core Data model - это схема БД - описание строк и колонок или записей и полей по другому.
В runtime режиме Core Data stack состоит из
- managed object context,
- managed object model,
- и persistent store coordinator.
В режиме runtime, модель данных комбинируется с двумя другими объектами:
- managed object context (NSManagedObjectContext)
- и persistent object store (NSPersistentStore) - обычно SQLite БД, но может быть и другой тип хранилища.
В runtime, каждый managed object является частью managed object context. Можно иметь любое количество managed object contexts в приложении в любое время. Одиночная сущность из модели данных может быть создана в нескольких экземплярах managed objects, но каждый экземпляр managed object должен быть в отдельном managed object context. При сохранении изменений сохраняется managed object context. Данные сохраняются в persistent store. Использование множества managed object contexts помогает реализовать undo и redo функции.
managed object - это объект созданный из сущности из модели данных и возможно из данных хранящихся в persistent store.
persistent object store в большинстве случаев это файл базы данных. В нем делается mapping между БД и объектами в режиме runtime. Также как можно иметь множество managed object contexts, также можно иметь множество persistent stores. В случае с persistent stores, NSPersistentStoreCoordinator выполняет управление; для управления managed object contexts нет соответсвующего объекта.
В вашем коде вы работаете с
- managed objects,
- persistent store coordinator,
- и managed object context.
Это самый просто сценарий. Если вам нужно множество managed object contexts, то можно их создать например для реализации undo команд. It will be the managed object context that actually commits a change to a persistent store.
В простейшем случае persistent store coordinator “координирует” одиночное хранилище.
Рассмотрим Master-Detail Application–based template в iOS или Cocoa Application template под Mac OS, в обоих случаях с Core Data.
// // AppDelegate.h // #import <UIKit/UIKit.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; @property (strong, nonatomic) UINavigationController *navigationController; @property (strong, nonatomic) UISplitViewController *splitViewController; @end
Реализация:
@implementation AppDelegate @synthesize window = _window; @synthesize managedObjectContext = __managedObjectContext; @synthesize managedObjectModel = __managedObjectModel; @synthesize persistentStoreCoordinator = __persistentStoreCoordinator; @synthesize navigationController = _navigationController; @synthesize splitViewController = _splitViewController; - (NSManagedObjectContext *)managedObjectContext
{ if (__managedObjectContext != nil)
{ return __managedObjectContext;
}
// Set a local variable to the persistent store coordinator
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{ // Create the managed object context with the persistent store coordinator
__managedObjectContext = [[NSManagedObjectContext alloc] init];
__managedObjectContext setPersistentStoreCoordinator:coordinator]; }
return __managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{ if (__persistentStoreCoordinator != nil)
{ return __persistentStoreCoordinator;
} NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent: // HERE IS THE NAME OF YOUR DATABASE FILE @”My_First_iOS_Project.sqlite”]; NSError *error = nil; __persistentStoreCoordinator [[NSPersistentStoreCoordinator alloc] // PICK UP THE MANAGED OBJECT MODEL FOR THE PERSISTENT STORE COORDINATOR initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{ NSLog(@”Unresolved error %@, %@”, error, [error userInfo]); abort();
} return __persistentStoreCoordinator;
}
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil)
{ return __managedObjectModel;
} NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@”My_First_iOS_Project “ withExtension:@”momd”]; __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return __managedObjectModel;
}
@end
Core Data model editor позволяет создавать множество версий модели. По умолчанию используется последняя, но можно изменить это.
Чтобы сделать запрос нужно создать fetch request и fetch request controller. Он будет взаимодействовать с Core Data stack.
При использовании для отображения данных UITableView, протокол для предоставления функциональности источника данных будет взаимодействовать с fetch request.
Класс MasterViewController принимает протокол NSFetched ResultsControllerDelegate. Данный протокол позволяет NSFetchedResultsController уведомлять его delegate о том что fetch результаты изменились.
- (NSFetchedResultsController *)fetchedResultsController { if (__fetchedResultsController != nil) { return __fetchedResultsController; } // Set up the fetched results controller. // Create the fetch request for the entity. NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; // Edit the entity name as appropriate. NSEntityDescription *entity = [NSEntityDescription entityForName:@”Event” inManagedObjectContext:self.managedObjectContext]; [fetchRequest setEntity:entity]; // Set the batch size to a suitable number. [fetchRequest setFetchBatchSize:20]; // Edit the sort key as appropriate. NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey: @”timeStamp” ascending:NO]; NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil]; [fetchRequest setSortDescriptors:sortDescriptors]; // Edit the section name key path and cache name if appropriate. // nil for section name key path means “no sections”. NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@”Master”]; aFetchedResultsController.delegate = self; self.fetchedResultsController = aFetchedResultsController; NSError *error = nil; if (![self.fetchedResultsController performFetch:&error]) { /* Replace this implementation with code to handle the error appropriately. abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. */ NSLog(@”Unresolved error %@, %@”, error, [error userInfo]); abort(); } return __fetchedResultsController; }