core-data
Базовый стек данных
Поиск…
замечания
Это реализация основного стека данных, который изначально помещается в файл AppDelegate
если проект создается с помощью Core Data при создании проекта. Эти функции также могут быть реализованы в отдельном классе для CoreDataStack.swift
. Одной из основных функций является получение NSManagedObjectContext.
Objective-C
- (NSManagedObjectContext *)managedObjectContext {...}
Swift 2
lazy var managedObjectContext: NSManagedObjectContext = {...}
Swift 3
lazy var persistentContainer: NSPersistentContainer = {...)
let managedObjectContext = persistentContainer.viewContext
Стек Core Data, который взаимодействует между объектами вашего приложения и внешними хранилищами данных. Стек Core Data обрабатывает все взаимодействия с внешними хранилищами данных, чтобы ваше приложение могло сосредоточиться на своей бизнес-логике. Стек состоит из трех основных объектов: контекста управляемого объекта ( NSManagedObjectContext
), постоянного координатора хранилища ( NSPersistentStoreCoordinator
) и модели управляемых объектов ( NSManagedObjectModel
).
NSManagedObjectModel
Экземпляр NSManagedObjectModel
описывает данные, к которым будет обращаться стек Core Data. NSManagedObjectModel
(часто называемый «мама») загружается в память в качестве первого шага при создании стека. Примером NSManagedObjectModel
является DataModel.momd. NSManagedObjectModel
определяет структуру данных
NSPersistentStoreCoordinator
NSPersistentStoreCoordinator
реализует объекты из данных в постоянном хранилище и передает эти объекты в запрашивающий NSManagedObjectContext
. Он создает новые экземпляры объектов в модели и извлекает существующие экземпляры из постоянного хранилища ( NSPersistentStore
). NSPersistentStoreCoordinator
также проверяет, что данные находятся в согласованном состоянии, которое соответствует определениям в NSManagedObjectModel
.
NSManagedObjectContext
Когда вы извлекаете объекты из постоянного хранилища, вы привозите временные копии на блокнот, где они образуют граф объектов (или набор графиков объектов). Затем вы можете изменить эти объекты, если вы фактически не сохраните эти изменения, однако постоянное хранилище остается неизменным.
Все управляемые объекты должны быть зарегистрированы в контексте управляемого объекта. Вы используете контекст для добавления объектов в граф объектов и удаления объектов из графа объектов. Контекст отслеживает сделанные вами изменения как с атрибутами отдельных объектов, так и с отношениями между объектами. Отслеживая изменения, контекст может предоставить вам отмену и повторную поддержку. Он также гарантирует, что при изменении отношений между объектами сохраняется целостность графика объекта.
При сохранении изменений контекст гарантирует, что ваши объекты находятся в допустимом состоянии. Изменения записываются в постоянное хранилище (или хранилища), новые записи добавляются для созданных вами объектов и удаляются записи для удаленных объектов.
Источник: Apple Core Data Programming: Инициализация основного стека данных
Пример Objective-C
Это простая, но надежная настройка данных ядра для iOS 10+. Существует два способа доступа к основным данным:
- viewContext .
viewContext
может использоваться только из основного потока и только для чтения. - strong enqueueCoreDataBlock . Все записи должны выполняться с помощью
enqueueCoreDataBlock
. Нет необходимости сохранять в конце, он автоматически сохранит. Все записи выводятся в очередь в операцииQueue, поэтому конфликты записи никогда не могут быть.
Обязательно никогда не используйте любые управляемые объекты из контекста в другом контексте. Также отмените все объекты, созданные или извлеченные в enqueueCoreDataBlock
поскольку контекст, который их поддерживает, будет уничтожен после выполнения блока.
// CoreDataManager.h
@interface CoreDataManager : NSObject
@property (nonatomic, readonly) NSManagedObjectContext * viewContext;
- (void)enqueueCoreDataBlock:(void (^)(NSManagedObjectContext* context))block;
@end
// CoreDataManager.m
@implementation NSManagedObjectContext(SaveIfNeeded)
-(BOOL) saveIfNeeded{
BOOL toReturn = YES;
if ([self hasChanges]) {
NSError *error;
toReturn = [self save:&error];
if (toReturn == NO || error)
{
//Here you should log to your analytics service
NSLog(@"--- Failed to commit data\n error: %@", error);
}
}
return toReturn;
}
@end
@interface CoreDataManager ()
@property (nonatomic, strong) NSPersistentContainer* persistentContainer;
@property (nonatomic, strong) NSOperationQueue* persistentContainerQueue;
@end
@implementation CoreDataManager
- (id)init
{
self = [super init]
if (self)
{
self.persistentContainer = [[NSPersistentContainer alloc] initWithName:@"PROJECT_NAME_ALSO_NAME_OF_MODEL" managedObjectModel:managedObjectModel];
[self.persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription * description, NSError * error) {
}];
self.persistentContainer.viewContext.automaticallyMergesChangesFromParent = YES;
_persistentContainerQueue = [[NSOperationQueue alloc] init];
_persistentContainerQueue.maxConcurrentOperationCount = 1;
_persistentContainerQueue.name = @"persistentContainerQueue";
dispatch_queue_t queue = dispatch_queue_create("persistentContainerQueue.dispatchQueue", DISPATCH_QUEUE_SERIAL);
_persistentContainerQueue.underlyingQueue = queue;
}
}
- (void)enqueueCoreDataBlock:(void (^)(NSManagedObjectContext* context))block{
void (^blockCopy)(NSManagedObjectContext*) = [block copy];
[self.persistentContainerQueue addOperation:[NSBlockOperation blockOperationWithBlock:^{
NSManagedObjectContext* context = self.persistentContainer.newBackgroundContext;
[context performBlockAndWait:^{
blockCopy(context);
[context saveIfNeeded];
}];
}]];
}
-(NSManagedObjectContext*) viewContext{
if (![NSThread mainThread]) {
//here you should log to you analytics service. If you are in developer mode you should crash to force you to fix this
NSLog(@"access context on wrong thread!!");
}
return self.persistentContainer.viewContext;
}
Пример Swift 2
// Core Data stack
lazy var applicationDocumentsDirectory: NSURL = {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1]
}()
lazy var managedObjectModel: NSManagedObjectModel = {
let modelURL = NSBundle.mainBundle().URLForResource("ProjectName", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch {
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
print("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// Core Data Saving support
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
let nserror = error as NSError
print("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}
}
}
Пример iOS 10 в Swift
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "ProjectName")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
func saveContext () {
let context = persistentContainer.viewContext
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
if context.hasChanges {
print("changes occured")
}else {
print("no changes occured")
}
}