gpt4 book ai didi

objective-c - 核心数据 : Merging children added on a background context is funky

转载 作者:搜寻专家 更新时间:2023-10-30 20:27:19 26 4
gpt4 key购买 nike

背景

  • 多线程核心数据应用程序

  • NSTreeControllerNSOutlineView 绑定(bind)

  • 在后台上下文的 NSOperation 中创建子对象

  • 使用 mergeChangesFromContextDidSaveNotification

    合并到主上下文中

Data Model

问题

  • 如果我将 20 个子对象创建操作排队,合并完成后,我在大纲 View 中只能看到大约 10-15 个子对象。

  • 如果我将最大并发操作数设置为 1,它会完美运行,我会看到 20 个 child 。

问题

我想做的事是不可能的吗?我可以看到核心数据如何难以成功进行合并。还是我的代码有问题?

代码

JGGroupController

 -(id)init {
self = [super init];
queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:10]; // If this is 1, it works like a dream. Anything higher and it bombs.
return self;
}

-(IBAction)addTrainingEntryChild:(id)sender {
moc = [[NSApp delegate] managedObjectContext];
JGTrainingBase *groupToAddTo = [[tree selectedObjects] objectAtIndex:0];
for (NSUInteger i = 0; i < 20; i++) {
JGAddChildrenObjectOperation *addOperation = [[JGAddChildrenObjectOperation alloc] init];
[addOperation addChildObjectToGroup:[groupToAddTo objectID]];
[queue addOperation:addOperation];
}
}

JGAddChildrenObjectOperation - NSOperation 子类

 -(id)addChildObjectToGroup:(NSManagedObjectID *)groupToAddToID_ {
groupToAddToObjectID = groupToAddToID_;
return self;
}

-(void)main {
[self startOperation];
JGTrainingBase *groupToAddTo = (JGTrainingBase *)[imoc objectWithID:groupToAddToObjectID];
JGTrainingBase *entryChildToAdd = [JGTrainingBase insertInManagedObjectContext:imoc];
[groupToAddTo addChildren:[NSSet setWithObject:entryChildToAdd]];
[imoc save];
[self cleanup];
[self finishOperation];
}

-(void)mergeChanges:(NSNotification *)notification {
NSManagedObjectContext *mainContext = [[NSApp delegate] managedObjectContext];
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
withObject:notification
waitUntilDone:YES];
}


-(void)startOperation {
// Omitted - Manage isExecuting, isPaused, isFinished etc flags

imoc = [[NSManagedObjectContext alloc] init];
[imoc setPersistentStoreCoordinator:[[NSApp delegate] persistentStoreCoordinator]];
[imoc setUndoManager:nil];
[imoc setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
[imoc setStalenessInterval:0];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:imoc];
}

-(void)finishOperation {
// Omitted - Manage isExecuting, isPaused, isFinished etc flags
}

最佳答案

您的操作正在使用商店中实体的不同“版本”。考虑以下操作顺序:

您创建了 2 个操作,我们称它们为 O:F 和 O:G,它们用于将子 F 和 G 添加到组 1,记为 G:1,子条目集为 [A,B,C,D,E ].

操作队列同时出队 O:F 和 O:G,因此它们都获取托管对象上下文和实体 G:1。

O:F 将 G:1 的 child 设置为 [A,B,C,D,E,F]。O:G 将 G:2 的 child 设置为 [A,B,C,D,E,G]。

无论哪种操作获胜,您最终都会得到 [A,B,C,D,E,F] 或 [A,B,C,D,E,G],两者都是商店中的值不正确。

我相信 CoreData 应该在其中一个线程中抛出一个乐观锁定错误,因为它的更改已经过时了。但我可能是错的。

最重要的是,您在不同步对象状态的情况下跨线程改变同一个对象。不是创建 20 个操作,而是创建 1 个添加 20 个对象的操作,但是您有一个核心架构问题,即尝试在不同步的情况下从多个线程改变同一个对象。

每次都会失败。

关于objective-c - 核心数据 : Merging children added on a background context is funky,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4168289/

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