多线程 – “在枚举期间变异的集合”on executeFetchRequest

多线程 – “在枚举期间变异的集合”on executeFetchRequest,第1张

概述我陷入了一个问题了几个小时,并已在stackoverflow上阅读了一切(并应用所有的建议),我现在正式需要帮助。 ; o) 这里是上下文: 在我的iPhone项目中,我需要在后台导入数据并将其插入到受管对象上下文中。根据这里找到的意见,这里是我在做什么: >保存主moc >使用主moc使用的持久存储协调器实例化后台moc >注册我的控制器作为背景moc的NSManagedObjectContex 我陷入了一个问题了几个小时,并已在stackoverflow上阅读了一切(并应用所有的建议),我现在正式需要帮助。 ; o)

这里是上下文:

在我的iPhone项目中,我需要在后台导入数据并将其插入到受管对象上下文中。根据这里找到的意见,这里是我在做什么:

>保存主moc
>使用主moc使用的持久存储协调器实例化后台moc
>注册我的控制器作为背景moc的NSManagedobjectContextDIDSaveNotification通知的观察者
>在后台线程中调用导入方法
>每次收到数据时,将其插入背景moc
>所有数据导入后,保存后台moc
>将更改合并到主moc中,在主线程上
>取消注册我的控制器作为通知的观察者
>重置并释放背景moc

有时(和随机),异常…

*** Terminating app due to uncaught exception 'NSGenericException',reason: '*** Collection <__NSCFSet: 0x5e0b930> was mutated while being enumerated...

…当我在后台moc上调用executeFetchRequest时抛出,以检查导入的数据是否已经存在于数据库中。我不知道是什么是突变的集合,因为没有什么运行导入方法之外。

我已经包括我的控制器和我的测试实体的整个代码(我的项目包括这两个类和应用程序委托,它是未经修改):

////  RootVIEwController.h//  FK1////  Created by Eric on 09/08/10.//  copyright (c) 2010 __MyCompanyname__. All rights reserved.//#import <CoreData/CoreData.h>@interface RootVIEwController : UItableVIEwController <NSFetchedResultsControllerDelegate> {    NSManagedobjectContext *managedobjectContext;    NSManagedobjectContext *backgroundMOC;}@property (nonatomic,retain) NSManagedobjectContext *managedobjectContext;@property (nonatomic,retain) NSManagedobjectContext *backgroundMOC;@end////  RootVIEwController.m//  FK1////  Created by Eric on 09/08/10.//  copyright (c) 2010 __MyCompanyname__. All rights reserved.//#import "RootVIEwController.h"#import "FK1Message.h"@implementation RootVIEwController@synthesize managedobjectContext;@synthesize backgroundMOC;- (voID)vIEwDIDLoad {    [super vIEwDIDLoad];    self.navigationController.toolbarHIDden = NO;    UIbarbuttonItem *refreshbutton = [[UIbarbuttonItem alloc] initWithbarbuttonSystemItem:UIbarbuttonSystemItemRefresh target:self action:@selector(refreshAction:)];    self.toolbaritems = [NSArray arrayWithObject:refreshbutton];}#pragma mark -#pragma mark ACTIONS- (voID)refreshAction:(ID)sender {    // If there already is an import running,we do nothing    if (self.backgroundMOC != nil) {        return;    }    // We save the main moc    NSError *error = nil;    if (![self.managedobjectContext save:&error]) {        NSLog(@"error = %@",error);        abort();    }    // We instantiate the background moc    self.backgroundMOC = [[[NSManagedobjectContext alloc] init] autorelease];    [self.backgroundMOC setPersistentStoreCoordinator:[self.managedobjectContext persistentStoreCoordinator]];    // We call the fetch method in the background thread    [self performSelectorInBackground:@selector(_importData) withObject:nil];}- (voID)_importData {    NSautoreleasePool *pool = [[NSautoreleasePool alloc] init];    [[NSNotificationCenter defaultCenter] addobserver:self selector:@selector(backgroundMOCDIDSave:) name:NSManagedobjectContextDIDSaveNotification object:self.backgroundMOC];             FK1Message *message = nil;    NSFetchRequest *fetchRequest = nil;    NSEntityDescription *entity = [NSEntityDescription entityForname:@"FK1Message" inManagedobjectContext:self.backgroundMOC];    nspredicate *predicate = nil;    NSArray *results = nil;    // fake import to keep this sample simple    for (NSInteger index = 0; index < 20; index++) {        predicate = [nspredicate predicateWithFormat:@"msgid == %@",[Nsstring stringWithFormat:@"%d",index]];        fetchRequest = [[[NSFetchRequest alloc] init] autorelease];        [fetchRequest setEntity:entity];        [fetchRequest setPredicate:predicate];        // The following line sometimes randomly throw the exception :        // *** Terminating app due to uncaught exception 'NSGenericException',reason: '*** Collection <__NSCFSet: 0x5b71a00> was mutated while being enumerated.        results = [self.backgroundMOC executeFetchRequest:fetchRequest error:NulL];        // If the message already exist,we retrIEve it from the database        // If it doesn't,we insert a new message in the database        if ([results count] > 0) {            message = [results objectAtIndex:0];        }        else {            message = [NSEntityDescription insertNewObjectForEntityForname:@"FK1Message" inManagedobjectContext:self.backgroundMOC];            message.msgid = [Nsstring stringWithFormat:@"%d",index];        }        // We update the message        message.updateDate = [NSDate date];    }    // We save the background moc which trigger the backgroundMOCDIDSave: method    [self.backgroundMOC save:NulL];    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedobjectContextDIDSaveNotification object:self.backgroundMOC];    [self.backgroundMOC reset]; self.backgroundMOC = nil;    [pool drain];}- (voID)backgroundMOCDIDSave:(NSNotification*)notification {        if (![NSThread isMainThread]) {        [self performSelectorOnMainThread:@selector(backgroundMOCDIDSave:) withObject:notification waitUntilDone:YES];        return;    }    // We merge the background moc changes in the main moc    [self.managedobjectContext mergeChangesFromContextDIDSaveNotification:notification];}@end////  FK1Message.h//  FK1////  Created by Eric on 09/08/10.//  copyright 2010 __MyCompanyname__. All rights reserved.//#import <CoreData/CoreData.h>@interface FK1Message :  NSManagedobject  {}@property (nonatomic,retain) Nsstring * msgid;@property (nonatomic,retain) NSDate * updateDate;@end// //  FK1Message.m//  FK1////  Created by Eric on 09/08/10.//  copyright 2010 __MyCompanyname__. All rights reserved.//#import "FK1Message.h"@implementation FK1Message #pragma mark -#pragma mark PROPERTIES@dynamic msgid;@dynamic updateDate;@end

这就是全部 !整个项目在这里。没有表视图,没有NSFetchedResultsController,没有别的背景线程在背景moc上导入数据。

在这种情况下,什么可以改变集合?

我很肯定我错过了一些明显的东西,它驱使我疯了。

编辑:

这里是完整的堆栈跟踪:

2010-08-10 10:29:11.258 FK1[51419:1b6b] *** Terminating app due to uncaught exception 'NSGenericException',reason: '*** Collection <__NSCFSet: 0x5d075b0> was mutated while being enumerated.<CFBasicHash 0x5d075b0 [0x25c6380]>{type = mutable set,count = 0,entrIEs =>}'*** Call stack at first throw:(    0   CoreFoundation                      0x0255d919 __exceptionPreprocess + 185    1   libobjc.A.dylib                     0x026ab5de objc_exception_throw + 47    2   CoreFoundation                      0x0255d3d9 __NSFastEnumerationMutationHandler + 377    3   CoreData                            0x02287702 -[NSManagedobjectContext executeFetchRequest:error:] + 4706    4   FK1                                 0x00002b1b -[RootVIEwController _fetchData] + 593    5   Foundation                          0x01d662a8 -[NSThread main] + 81    6   Foundation                          0x01d66234 __NSThread__main__ + 1387    7   libSystem.B.dylib                   0x9587681d _pthread_start + 345    8   libSystem.B.dylib                   0x958766a2 thread_start + 34)terminate called after throwing an instance of 'NSException'
解决方法 OK,我想我已经解决了我的问题,我必须感谢这个博客文章从Fred McCann的:

http://www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/

问题似乎来自于我在主线程而不是后台线程实例化我的后台moc。当苹果告诉每个线程需要有自己的moc,你必须认真对待:每个moc必须在线程中实例化,将使用它!

移动以下行…

// We instantiate the background mocself.backgroundMOC = [[[NSManagedobjectContext alloc] init] autorelease];[self.backgroundMOC setPersistentStoreCoordinator:[self.managedobjectContext persistentStoreCoordinator]];

…在_importData方法(刚才注册控制器作为通知的观察者)解决问题。

感谢您的帮助,Peter。感谢Fred McCann的宝贵博客!

@H_502_76@ 总结

以上是内存溢出为你收集整理的多线程 – “在枚举期间变异的集合”on executeFetchRequest全部内容,希望文章能够帮你解决多线程 – “在枚举期间变异的集合”on executeFetchRequest所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1049219.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存