我尝试使用NSManagedDocument
构建一种在Core Data中保存数据的现代方法。一切正常,但如果我重新启动应用程序(终止并再次运行),我将在我的数据库中获得重复的实体,有时应用程序崩溃并出现错误:
此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
)作为属性。
Create
子类NSManagedObject
(Xcode自动生成的子类)的类别Book
具有以下实现,以检查数据库中是否已存在ISBN。这应该返回一个新创建的实体或现有的实体,并在发生一些错误时返回nil,例如有2本书具有相同的ISBN。
+(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
。
答案 0 :(得分:1)
这个建议不会解决你的问题,但无论如何我都会把它解决掉。我曾经像你一样使用原始形式的coreData,直到我发现了MagicalRecord。太棒了。你应该检查一下。 https://github.com/magicalpanda/MagicalRecord
好处是它将所有CoreData代码打包成整齐的易消化代码。它负责管理线程中的上下文关系。
答案 1 :(得分:0)
所有实例化代码必须位于dispatch_once块中。您希望确保只打开一次文档。
此链接显示所有实例化代码必须位于dispatch_once块中。
How do I implement an Objective-C singleton that is compatible with ARC?