core-data
Stack di dati core
Ricerca…
Osservazioni
Questa è un'implementazione del Core Data Stack che viene inizialmente inserito nel file AppDelegate
se il progetto viene creato con Core Data al momento della creazione del progetto. Queste funzioni possono anche essere implementate in una classe separata per CoreDataStack.swift
. Una delle funzioni principali è ottenere NSManagedObjectContext.
Objective-C
- (NSManagedObjectContext *)managedObjectContext {...}
Swift 2
lazy var managedObjectContext: NSManagedObjectContext = {...}
Swift 3
lazy var persistentContainer: NSPersistentContainer = {...)
let managedObjectContext = persistentContainer.viewContext
Lo stack di dati principali che comunica tra gli oggetti nell'applicazione e gli archivi di dati esterni. Lo stack di Core Data gestisce tutte le interazioni con gli archivi di dati esterni in modo che l'applicazione possa concentrarsi sulla sua logica di business. Lo stack è costituito da tre oggetti primari: il contesto dell'oggetto gestito ( NSManagedObjectContext
), il coordinatore NSPersistentStoreCoordinator
permanente ( NSPersistentStoreCoordinator
) e il modello oggetto gestito ( NSManagedObjectModel
).
NSManagedObjectModel
L'istanza di NSManagedObjectModel
descrive i dati a cui sarà possibile accedere dallo stack dei Core Data. NSManagedObjectModel
(spesso chiamato "mamma") viene caricato in memoria come primo passo nella creazione dello stack. Un esempio di NSManagedObjectModel
è DataModel.momd. Il NSManagedObjectModel
definisce la struttura dei dati
NSPersistentStoreCoordinator
NSPersistentStoreCoordinator
realizza oggetti dai dati nell'archivio permanente e li inoltra al NSManagedObjectContext
richiedente. Crea nuove istanze delle entità nel modello e recupera le istanze esistenti da un archivio persistente ( NSPersistentStore
). NSPersistentStoreCoordinator
verifica inoltre che i dati siano in uno stato coerente che corrisponde alle definizioni in NSManagedObjectModel
.
NSManagedObjectContext
Quando recuperi oggetti da un archivio persistente, porti delle copie temporanee sul blocco da disegno dove formano un oggetto grafico (o una raccolta di grafici di oggetti). È quindi possibile modificare tali oggetti, a meno che non si salvino effettivamente tali modifiche, tuttavia, l'archivio permanente rimane inalterato.
Tutti gli oggetti gestiti devono essere registrati con un contesto dell'oggetto gestito. Si utilizza il contesto per aggiungere oggetti al grafico dell'oggetto e rimuovere oggetti dal grafico dell'oggetto. Il contesto tiene traccia delle modifiche apportate, sia agli attributi degli oggetti individuali sia alle relazioni tra gli oggetti. Tracciando le modifiche, il contesto è in grado di fornire supporto di annullamento e ripetizione per te. Garantisce inoltre che se si modificano le relazioni tra gli oggetti, viene mantenuta l'integrità del grafico dell'oggetto.
Quando salvi le modifiche, il contesto garantisce che gli oggetti siano in uno stato valido. Le modifiche vengono scritte nell'archivio permanente (o nei negozi), vengono aggiunti nuovi record per gli oggetti creati e i record vengono rimossi per gli oggetti eliminati.
Fonte: Apple Core Data Programming: inizializzazione dello stack dei dati principali
Esempio-C Esempio
Questa è una semplice ma robusta configurazione dei dati di base per iOS 10+. Ci sono esattamente due modi per accedere ai dati principali:
- viewContext .
viewContext
può essere utilizzato solo dal thread principale e solo per la lettura. - strong enqueueCoreDataBlock . Tutta la scrittura dovrebbe essere fatta usando
enqueueCoreDataBlock
. Non è necessario salvare alla fine si salverà automaticamente. Tutte le scritture vengono accodate in un'operazioneQueue, quindi non ci possono essere conflitti di scrittura.
Assicurati di NON utilizzare MAI oggetti gestiti dal contesto in un altro contesto. Inoltre, elimina tutti gli oggetti che sono stati creati o recuperati in enqueueCoreDataBlock
poiché il contesto che li supporta verrà distrutto dopo l'esecuzione del blocco.
// 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 Esempio
// 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 Esempio in 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")
}
}