gpt4 book ai didi

ios - 在后台上下文中保存核心数据时出现 NSInternalInconsistencyException

转载 作者:行者123 更新时间:2023-11-29 13:31:09 27 4
gpt4 key购买 nike

我已经阅读了有关此错误的所有内容,但仍然无法确定为什么它会在我的应用程序中发生。

使用后台上下文保存多个 Core Data 对象时出现以下错误:

*** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“保存前无法处理挂起的更改。100 次尝试后上下文仍然是脏的。通常这种递归脏化是由错误的验证方法引起的、-willSave 或通知处理程序。

在下面的代码中,ArticleManageraddArticle 在主线程中循环调用。可能有 0-200 多篇文章要添加。此错误通常发生在文章计数 100-150 之间。

//ArticleManager.m

-(id)init
{
... //normal init stuff
dispatch_queue_t request_queue = dispatch_queue_create("com.app.articleRequest", NULL);
}

-(void) addArticle:(Article *)article withURLKey:(NSString *)url
{
//check if exists
if ([downloadedArticles objectForKey:url] == nil && article != nil)
{
//add locally
[downloadedArticles setObject:article forKey:url];

//save to core data
SaveArticle *saveArticle = [[SaveArticle alloc] init];
[saveArticle saveArticle:article withURL:url onQueue:request_queue];
}
}
//SaveArticle.m

@implementation SaveArticle

@synthesize managedObjectContext;
@synthesize backgroundContext;

-(id)init
{
if (![super init]) return nil;

AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
managedObjectContext = [appDelegate managedObjectContext];

backgroundContext = [[NSManagedObjectContext alloc] init];
[backgroundContext setPersistentStoreCoordinator:[managedObjectContext persistentStoreCoordinator]];

return self;
}

-(void)saveArticle:(Article *)article withURL:(NSString *)url onQueue:(dispatch_queue_t)queue
{
//save persistently in the background
dispatch_async(queue, ^{
ArticleCache *articleCacheObjectModel = (ArticleCache *)[NSEntityDescription insertNewObjectForEntityForName:@"ArticleCache" inManagedObjectContext:backgroundContext];

if (article != nil)
{
[articleCacheObjectModel setArticleHTML:article.articleHTML];
[articleCacheObjectModel setUrl:url];

NSError *error;

//Save the background context and handle the save notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:backgroundContext];

if(![backgroundContext save:&error]) //ERROR OCCURS HERE, after many saves
{
//This is a serious error saying the record
//could not be saved. Advise the user to
//try again or restart the application.
}

[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:backgroundContext];

}
});
}

/* Save notification handler for the background context */
- (void)backgroundContextDidSave:(NSNotification *)notification {
/* Make sure we're on the main thread when updating the main context */
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
withObject:notification
waitUntilDone:NO];
return;
}

/* merge in the changes to the main context */
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}

@end

最佳答案

好的,所以阅读官方文档还是有点用的。

来自 Apple(强调我的):

Concurrency

Core Data uses thread (or serialized queue) confinement to protect managed objects and managed object contexts (see “Concurrency with Core Data”). A consequence of this is that a context assumes the default owner is the thread or queue that allocated it—this is determined by the thread that calls its init method. You should not, therefore, initialize a context on one thread then pass it to a different thread. Instead, you should pass a reference to a persistent store coordinator and have the receiving thread/queue create a new context derived from that. If you use NSOperation, you must create the context in main (for a serial queue) or start (for a concurrent queue).

所以我的问题是我在主线程上初始化了后台上下文,但随后通过 dispatch_async 使用了 Grand Central Dispatch,它在后台线程上执行保存(使用创建的上下文主线程)。

我通过将上下文初始化添加到背景 block 来修复它:

-(void)saveArticle:(Article *)article withURL:(NSString *)url onQueue:(dispatch_queue_t)queue
{
//save persistently in the background
dispatch_async(queue, ^{

NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] init];
[backgroundContext setPersistentStoreCoordinator:[managedObjectContext persistentStoreCoordinator]];

ArticleCache *articleCacheObjectModel = (ArticleCache *)[NSEntityDescription insertNewObjectForEntityForName:@"ArticleCache" inManagedObjectContext:backgroundContext];

if (article != nil)
{
[articleCacheObjectModel setArticleHTML:article.articleHTML];
[articleCacheObjectModel setUrl:url];

NSError *error;

//Save the background context and handle the save notification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(backgroundContextDidSave:)
name:NSManagedObjectContextDidSaveNotification
object:backgroundContext];

if(![backgroundContext save:&error])
{
//This is a serious error saying the record
//could not be saved. Advise the user to
//try again or restart the application.
}

[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSManagedObjectContextDidSaveNotification
object:backgroundContext];
}
});
}

关于ios - 在后台上下文中保存核心数据时出现 NSInternalInconsistencyException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11871470/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com