我正在实现CoreData堆栈 https://stackoverflow.com/a/24663533(图片中的选项A)但它以意想不到的方式工作。
我有 rootContext (NSPrivateQueueConcurrencyType),它有两个子节点: uiContext (NSMainQueueConcurrencyType)用于提取对象, syncContext (NSPrivateQueueConcurrencyType)用于异步数据编辑。
正如我想的那样,当我在performBlock(后台队列)中的syncContext中保存内容时,更改将传播到rootContext,但是直到我观察NSManagedObjectContextDidSaveNotification并合并通知中的更改时才会更改uiContext。但是在syncContext保存后立即反映出更改。
我的第一个问题是:为什么没有人工合并更新uiContext?
我的第二个问题:为什么在syncContext保存后在后台(而不是主线程)上修改了rootContext?前段时间我问过关于" CoreData无法解决问题的问题" MagicalRecord 'CoreData could not fulfill a fault' error with MagicalRecord的问题,但我没有得到答案,所以我决定找到没有外部库的解决方案。
看来,主线程正在读取对象属性,同一对象在后台被删除,而主线程上的操作员仍然没有返回控制权。
这是我的源代码:
#import <CoreData/CoreData.h>
#import "DataLayer.h"
#import "Person.h"
@interface DataLayer ()
@property (nonatomic, strong) NSManagedObjectModel *model;
@property (nonatomic, strong) NSPersistentStoreCoordinator *coordinator;
@property (nonatomic, strong) NSManagedObjectContext *rootContext;
@property (nonatomic, strong) NSManagedObjectContext *uiContext;
@property (nonatomic, strong) NSManagedObjectContext *syncContext;
@end
@implementation DataLayer
+ (void)load
{
[self instance];
}
+ (DataLayer *)instance
{
static DataLayer *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[DataLayer alloc] init];
});
return instance;
}
- (instancetype)init
{
self = [super init];
if (self) {
[self initModel];
[self initCoordinator];
[self initContexts];
[self observeContextSaveNotification];
[self startTesting];
}
return self;
}
- (void)initModel
{
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
self.model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
}
- (void)initCoordinator
{
NSURL *directory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *storeURL = [directory URLByAppendingPathComponent:@"Model.sqlite"];
NSError *error = nil;
self.coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model];
if (![self.coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
- (void)initContexts
{
self.rootContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.rootContext.persistentStoreCoordinator = self.coordinator;
self.uiContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.uiContext.parentContext = self.rootContext;
self.syncContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.syncContext.parentContext = self.rootContext;
}
- (void)observeContextSaveNotification
{
// [[NSNotificationCenter defaultCenter] addObserver:self
// selector:@selector(onManagedObjectContextDidSaveNotification:)
// name:NSManagedObjectContextDidSaveNotification
// object:nil];
}
- (void)onManagedObjectContextDidSaveNotification:(NSNotification *)notification
{
// NSManagedObjectContext *context = notification.object;
// if (context != self.uiContext) {
// [self.uiContext mergeChangesFromContextDidSaveNotification:notification];
// }
}
- (void)startTesting
{
NSArray *personsBeforeSave = [self fetchEntities:@"Person" fromContext:self.uiContext];
NSLog(@"Before save: %i persons in syncContext", [personsBeforeSave count]); // Before save: 0 persons in syncContext
[self.syncContext performBlock:^{
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.syncContext];
person.firstName = @"Alexander";
NSError *error = nil;
[self.syncContext save:&error];
if (error) {
NSLog(@"Error during save: %@", error);
}
NSArray *personsAfterSaveFromBackground = [self fetchEntities:@"Person" fromContext:self.rootContext];
NSLog(@"After save from background: %i persons in rootContext", [personsAfterSaveFromBackground count]); // After save from background: 1 persons in rootContext
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *personsAfterSaveFromMain = [self fetchEntities:@"Person" fromContext:self.uiContext];
NSLog(@"After save from main: %i persons in uiContext", [personsAfterSaveFromMain count]); // After save from main: 1 persons in uiContext
});
}];
}
- (NSArray *)fetchEntities:(NSString *)entity fromContext:(NSManagedObjectContext *)context
{
NSError *error = nil;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entity];
NSArray *result = [context executeFetchRequest:request error:&error];
if (error) {
NSLog(@"Error during fetch %@: %@", entity, error);
return nil;
}
return result;
}
@end
答案 0 :(得分:0)
它们未合并到UI上下文中。您是手动提取它们。
当您在syncContext中保存时,数据会被推送到rootContext中。数据未合并到uiContext中。但是,当您执行提取时,提取会从父上下文中提取数据。
您可以在registeredObjects
。