core-data
Core Data Stack
Sök…
Anmärkningar
Detta är en implementering av Core Data Stack som initialt placeras i AppDelegate
filen om projektet skapas med Core Data när projekt skapas. Dessa funktioner kan också implementeras i separat klass för CoreDataStack.swift
. En av de viktigaste funktionerna är att få NSManagedObjectContext.
Objective-C
- (NSManagedObjectContext *)managedObjectContext {...}
Snabb 2
lazy var managedObjectContext: NSManagedObjectContext = {...}
Snabb 3
lazy var persistentContainer: NSPersistentContainer = {...)
let managedObjectContext = persistentContainer.viewContext
Core Data-stacken som kommunicerar mellan objekten i din applikation och externa datalagrar. Core Data-stacken hanterar alla interaktioner med de externa datalagren så att din applikation kan fokusera på dess affärslogik. Bunten består av tre primära objekt: det hanterade objektets sammanhang ( NSManagedObjectContext
), den persistenta butikskoordinatorn ( NSPersistentStoreCoordinator
) och den hanterade objektmodellen ( NSManagedObjectModel
).
NSManagedObjectModel
NSManagedObjectModel
beskriver de data som kommer att nås av Core Data-stacken. NSManagedObjectModel
(ofta kallad ”mamma”) laddas i minnet som det första steget i skapandet av stacken. Ett exempel på NSManagedObjectModel
är DataModel.momd. NSManagedObjectModel
definierar strukturen för data
NSPersistentStoreCoordinator
NSPersistentStoreCoordinator
inser objekt från data i den ihållande lagringen och skickar dessa objekt till den begärande NSManagedObjectContext
. Det skapar nya instanser av enheterna i modellen och hämtar befintliga instanser från en ihållande butik ( NSPersistentStore
). NSPersistentStoreCoordinator
verifierar också att uppgifterna är i ett konsekvent tillstånd som matchar definitionerna i NSManagedObjectModel
.
NSManagedObjectContext
När du hämtar objekt från en ihållande butik tar du med tillfälliga kopior på skrapplattan där de bildar ett objektdiagram (eller en samling av objektgrafer). Du kan sedan ändra dessa objekt, såvida du inte sparar ändringarna, men den bestående butiken förblir oförändrad.
Alla hanterade objekt måste registreras med ett hanterat objektssammanhang. Du använder sammanhanget för att lägga till objekt i objektgrafen och ta bort objekt från objektgrafen. Kontexten spårar de ändringar du gör, både till enskilda objekts attribut och till förhållandena mellan objekt. Genom att spåra förändringar kan kontexten ge ångra och göra om support för dig. Det säkerställer också att om du ändrar förhållanden mellan objekt, hålls objekts grafens integritet.
När du sparar ändringar säkerställer sammanhanget att dina objekt är i giltigt tillstånd. Ändringarna skrivs till den bestående butiken (eller butikerna), nya poster läggs till för objekt du skapade och poster tas bort för objekt som du har tagit bort.
Källa: Apple Core Data Programming: Initiera Core Data Stack
Objekt-C-exempel
Detta är en enkel men robust inställning av kärndata för iOS 10+. Det finns exakt två sätt att få tillgång till kärndata:
- viewContext .
viewContext
kan endast användas från huvudtråden och endast för läsning. - stark enqueueCoreDataBlock . All skrivning ska göras med
enqueueCoreDataBlock
. Det finns inget behov av att spara i slutet kommer det automatiskt att spara. Alla skrivningar är förknippade i en operationQueue så det kan aldrig finnas skrivkonflikter.
Se till att ALDRIG använda förvaltade objekt från sammanhang i ett annat sammanhang. Kassera också alla objekt som skapas eller hämtas i enqueueCoreDataBlock
eftersom det sammanhang som stöder dem kommer att förstöras efter att blocket har körts.
// 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;
}
Exempel på 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-exempel i 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")
}
}