0

我试图建立一种现代的方式来保存 Core Data 中的数据,使用NSManagedDocument. 一切正常,除了如果我重新启动应用程序(终止它并再次运行它)我会在我的数据库中得到重复的实体,有时应用程序会因错误而崩溃:

这个 NSPersistentStoreCoordinator 没有持久存储。它无法执行保存操作。

我认为在不同的线程中发生了一些事情并制造了麻烦,但我无法弄清楚我必须改变什么。希望你们中的一个可以帮助我。

我的班级Database有这个实现

+ (Database *)sharedDatabase
{
static Database *sharedInstance;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    url = [url URLByAppendingPathComponent:@"Default Database"];
    sharedInstance = [[self alloc] initWithFileURL:url];
    sharedInstance.isCreating = NO;
    sharedInstance.isOpening = NO;
});
if (![[NSFileManager defaultManager] fileExistsAtPath:[sharedInstance.fileURL path]]) {
    if (!sharedInstance.isCreating) {
        sharedInstance.isCreating = YES;
        [sharedInstance saveToURL:sharedInstance.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
            sharedInstance.isCreating = NO;
        }];
    }
} else if(sharedInstance.documentState == UIDocumentStateClosed){
    if (!sharedInstance.isOpening) {
        sharedInstance.isOpening = YES;
        [sharedInstance openWithCompletionHandler:^(BOOL success) {
            sharedInstance.isOpening = NO;
        }];
    }
}
return sharedInstance;
}

然后我创建了一个数据模型,其中包含一个名为Book. 为了简单起见,它只有一个isbn(类型NSString)作为属性。子类( Xcode 自动生成Create的子类)的类别具有以下实现来检查数据库中是否已存在 ISBN。这应该返回一个新创建的实体或现有实体,并在发生某些错误时返回 nil,例如有 2 本书具有相同的 ISBN。NSManagedObjectBook

+(Book *) bookWithISBN:(NSString *)isbn inManagedObjectContext:(NSManagedObjectContext *)context
{
Book *book;

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Book"];
request.predicate = [NSPredicate predicateWithFormat:@"isbn LIKE %@", isbn];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"isbn" ascending:YES];
request.sortDescriptors = @[sortDescriptor];

NSError *error;
NSArray *matches = [context executeFetchRequest:request error:&error];
if (!matches || (matches.count > 1)) {
    return nil;
} else if(matches.count == 0){
    book = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:context];
    book.isbn = isbn;
}else{
    book = [matches lastObject];
}
return book;
}

所以现在如果我在第一次运行应用程序时调用这个方法,[Book bookWithISBN:@"1234567890" inManagedObjectContext:[Database sharedDatabase].managedObjectContext]它将在我的数据库中创建一个实体。如果我终止应用程序并再次运行它,它会再次创建相同的实体。第二次我终止并再次运行它时它会返回nil(应该是因为有 2 本书具有相同的 ISBN)。

我在这个项目中使用 ARC。

可能的解决方案

我现在已经尝试了几个小时,直到现在,如果我不子类化UIManagedDocument而是创建一个继承自NSObject并包含UIManagedDocument. 有人知道这真的是正确的解决方案吗?因为我认为应该可以子类化UIManagedDocument

4

2 回答 2

1

这个建议不会解决你眼前的问题,但无论如何我都会把它放在那里。在我发现 MagicalRecord 之前,我曾经像你一样使用原始形式的 coreData。太棒了。你应该检查一下。https://github.com/magicalpanda/MagicalRecord

好处是它将所有 CoreData 代码打包成简洁易懂的代码。它负责管理线程中的上下文关系。

于 2013-02-27T09:19:49.770 回答
0

所有实例化代码必须驻留在 dispatch_once 块中。您要确保只打开文档一次。

此链接显示所有实例化代码必须在 dispatch_once 块内。

如何实现与 ARC 兼容的 Objective-C 单例?

于 2013-02-27T08:52:40.997 回答