core-data
Podstawowy stos danych
Szukaj…
Uwagi
Jest to implementacja stosu danych podstawowych, który jest początkowo umieszczany w pliku AppDelegate
, jeśli projekt jest tworzony przy użyciu danych podstawowych podczas tworzenia projektu. Funkcje te można również zaimplementować w osobnej klasie dla CoreDataStack.swift
. Jedną z głównych funkcji jest uzyskanie NSManagedObjectContext.
Cel C
- (NSManagedObjectContext *)managedObjectContext {...}
Swift 2
lazy var managedObjectContext: NSManagedObjectContext = {...}
Szybki 3
lazy var persistentContainer: NSPersistentContainer = {...)
let managedObjectContext = persistentContainer.viewContext
Stos danych podstawowych, który komunikuje się między obiektami w aplikacji a zewnętrznymi magazynami danych. Stos danych podstawowych obsługuje wszystkie interakcje z zewnętrznymi magazynami danych, dzięki czemu aplikacja może skupić się na logice biznesowej. Stos składa się z trzech podstawowych obiektów: kontekstu obiektu zarządzanego ( NSManagedObjectContext
), koordynatora przechowywania trwałego ( NSPersistentStoreCoordinator
) i modelu obiektu zarządzanego ( NSManagedObjectModel
).
NSManagedObjectModel
Instancja NSManagedObjectModel
opisuje dane, które będą dostępne przez stos danych podstawowych. NSManagedObjectModel
(często nazywany „mamą”) jest ładowany do pamięci jako pierwszy krok w tworzeniu stosu. Przykładem NSManagedObjectModel
jest DataModel.momd. NSManagedObjectModel
określa strukturę danych
NSPersistentStoreCoordinator
NSPersistentStoreCoordinator
realizuje obiekty z danych w trwałym magazynie i przekazuje te obiekty do żądającego NSManagedObjectContext
. Tworzy nowe wystąpienia encji w modelu i pobiera istniejące wystąpienia z trwałego magazynu ( NSPersistentStore
). NSPersistentStoreCoordinator
sprawdza również, czy dane są w spójnym stanie zgodnym z definicjami w NSManagedObjectModel
.
NSManagedObjectContext
Podczas pobierania obiektów z trwałego magazynu, przenosisz tymczasowe kopie na notatnik, gdzie tworzą wykres obiektów (lub zbiór wykresów obiektów). Następnie możesz zmodyfikować te obiekty, chyba że faktycznie zapiszesz te zmiany, jednak trwały magazyn pozostaje niezmieniony.
Wszystkie zarządzane obiekty muszą być zarejestrowane w kontekście zarządzanych obiektów. Kontekst służy do dodawania obiektów do wykresu obiektów i usuwania obiektów z wykresu obiektów. Kontekst śledzi wprowadzane zmiany, zarówno w odniesieniu do atrybutów poszczególnych obiektów, jak i relacji między obiektami. Śledząc zmiany, kontekst może zapewnić obsługę cofania i ponawiania. Zapewnia również, że jeśli zmienisz relacje między obiektami, zachowana zostanie integralność grafu obiektowego.
Podczas zapisywania zmian kontekst zapewnia, że Twoje obiekty są w poprawnym stanie. Zmiany są zapisywane w trwałym magazynie (lub sklepach), nowe rekordy są dodawane do obiektów, które utworzyłeś, a rekordy są usuwane dla obiektów, które usunąłeś.
Źródło: Programowanie podstawowych danych Apple: Inicjowanie stosu danych podstawowych
Przykład celu C
Jest to prosta, ale solidna konfiguracja podstawowych danych dla systemu iOS 10+. Istnieją dokładnie dwa sposoby dostępu do danych podstawowych:
- viewContext .
viewContext
może być używany tylko z głównego wątku i tylko do odczytu. - strong enqueueCoreDataBlock . Całe pisanie powinno odbywać się za pomocą
enqueueCoreDataBlock
. Nie ma potrzeby zapisywania na końcu - zapisuje się automatycznie. Wszystkie zapisy są kolejkowane w kolejce operacji, więc nigdy nie będzie konfliktów zapisu.
Pamiętaj, aby NIGDY nie używać żadnych obiektów zarządzanych z kontekstu w innym kontekście. Odrzuć również wszystkie obiekty, które są tworzone lub pobierane w enqueueCoreDataBlock
ponieważ kontekst, który je popiera, zostanie zniszczony po wykonaniu bloku.
// 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;
}
Przykład 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()
}
}
}
Przykład iOS 10 w 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")
}
}