核心数据并发 - 集合在被枚举时发生了变异
Posted
技术标签:
【中文标题】核心数据并发 - 集合在被枚举时发生了变异【英文标题】:Core Data Concurrency - Collection was mutated while being enumerated 【发布时间】:2012-12-10 16:29:21 【问题描述】:我在我的核心数据应用程序中添加了一些名为Transaction
s 的对象。这些交易与一个帐户相关联。
我想在所有交易都保存后更新帐户金额。有时会出现并发异常
“枚举时集合发生了变异”
NSArray *matches = [managedObjectContext executeFetchRequest:request error:&error];
accountManagedObjectWithId
方法中的行。
//TransactionsManager
- (BOOL)addRepeatTransaction:(Transaction *)transaction
Account *accountTrx = transaction.account;
double accountAmount = accountTrx.amount;
for (int i =0; i<nbRepeat; i++)
accountAmount +=transactionBiz.amount;
[[Persister instance] registerTransaction:transaction];
[[Persister instance]editAmountAccount:transaction.account amount:accountAmount];
[[Persister instance]saveContext];
return YES;
//Persister
-(id)init
if (self = [super init])
managedObjectContext = [appDelegate managedObjectContext];
return self;
return nil;
-(BOOL)registerTransaction:(Transaction *)transaction
TransactionManagedObject *transactionsRow = (TransactionsManagedObject *)[NSEntityDescription insertNewObjectForEntityForName:@"Transactions" inManagedObjectContext:managedObjectContext];
transactionsRow.idTransaction = [NSNumber numberWithInt:transaction.idTransaction];
transactionsRow.name = transaction.name;
transactionsRow.amount = [NSNumber numberWithDouble:transaction.amount];
[...]
transactionsRow.account = [[Finder instance] accountManagedObjectWithId:transaction.account.idAccount];
return YES;
-(BOOL)editAmountAccount:(Account *)asset amount:(double)amount
AccountManagedObject *accountRow = [[Finder instance] accountManagedObjectWithId:account.idAccount];
accountRow.amount = [NSNumber numberWithDouble:amount];
return YES;
-(AccountManagedObject *)accountManagedObjectWithId:(NSInteger)idAccount
NSFetchRequest *request = [[NSFetchRequest alloc]init];
[request setEntity:[NSEntityDescription entityForName:@"Accounts" inManagedObjectContext:managedObjectContext]];
//Predicate
NSString *recordedIdAccount = @"idAccount";
NSNumber *numberIdAccount = [NSNumber numberWithInt:idAccount];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", recordedIdAccount,numberIdAccount];
[request setPredicate:predicate];
//Execute
NSError *error;
NSArray *matches = [managedObjectContext executeFetchRequest:request error:&error];
NSInteger nbResult = [matches count];
if(nbResult==1)
return [matches objectAtIndex:0];
if(nbResult==0)
[...]
return nil;
if(nbResult>0)
[...]
return nil;
return nil;
//UI call
[...]
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
//Save
[[TransactionsManager instance] addRepeatTransaction:transactionToAdd];
dispatch_async(dispatch_get_main_queue(), ^
//Call the delegate
[self.delegate theSaveButtonOnTheAddTransactionTVCWasTapped:self];
);
);
@瓦伦丁·拉杜
我已经尝试过了,但问题仍然存在。我必须为每次添加设置一个managedObjectContext
。这是有效的,但它会减慢应用程序的速度。这是正确的做法吗?
-(BOOL)registerTransaction:(Transaction *)transaction
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:[[self managedObjectContext] persistentStoreCoordinator]];
TransactionsManagedObject *transactionsRow = (TransactionsManagedObject *)[NSEntityDescription insertNewObjectForEntityForName:@"Transactions" inManagedObjectContext:moc];
transactionsRow.idTransaction = [NSNumber numberWithInt:transaction.idTransaction];
transactionsRow.name = transaction.name;
transactionsRow.amount = [NSNumber numberWithDouble:transaction.amount];
[...]
transactionsRow.account = [[Finder instance] accountManagedObjectWithId:transaction.account.idAccount andManagedContext:moc]];
NSError *error = nil;
if (![moc save:&error])
[[ErrorManager instance] addError:error];
return NO;
return YES;
【问题讨论】:
您能提供一个独立的答案吗?这里的细节太多了。你的后台线程在哪里?谢谢。 【参考方案1】:您似乎只使用一个上下文,如果您在核心数据对象上执行并行操作,这是错误的。每个线程都应该有一个上下文,并在每次保存时合并上下文。 Apple 的核心数据指南对此进行了更详细的讨论。
【讨论】:
我已经尝试过了,但问题仍然存在。我必须为每次添加设置一个 managedObjectContext。这是有效的,但它会减慢应用程序的速度。这是正确的做法吗? 是的,它正在工作。我的错误是我尝试了您的解决方案,但方法不正确,所以我认为它没有醒来。如果我错了,请纠正我,但是必须在第二个线程上使用和创建 backgroundManagedContext 并且不能在主线程上创建并在第二个线程上使用? 我觉得现在可以了。非常感谢您的回答! @ValentinRadu 根据文档,创建上下文的线程很重要:“您必须在将使用它的线程上创建托管上下文。” developer.apple.com/library/mac/#documentation/cocoa/conceptual/…以上是关于核心数据并发 - 集合在被枚举时发生了变异的主要内容,如果未能解决你的问题,请参考以下文章
崩溃 - “集合 <CALayerArray: 0x645dfc0> 在枚举时发生了变异。”
NSArraym 在枚举时发生了变异,sqlite3 while 循环?