核心数据/ NSOperation:在枚举和删除对象时崩溃
||
我有一个基于核心数据的应用程序,该应用程序具有一个对象(列表)与许多对象(列表项)的关系。我正在努力在设备之间同步数据,并且作为其中一部分,我从后台线程中的XML文件中导入列表(通过NSOperation子类)。
当我更新现有列表时,我删除了所有旧列表项(从特定于该线程的NSManagedObjectContext中),并用XML文件中的新列表项替换了它们。删除操作通过枚举以下项来处理:该列表:
for (ListItemCD *item in listToUpdate.listItems) {
[self.importContext deleteObject:item];
}
但是,有时,在枚举期间会崩溃:
*由于未捕获的异常\'NSGenericException \'而终止应用程序,原因:\'*集合<_NSFaultingMutableSet:0x4fcfcb0>在枚举时发生了突变。
我不确定从哪里开始寻找导致该问题的原因。枚举发生时,我不会在代码的任何其他部分修改列表。可以同时存在多个线程,因为导入/更新了不同的列表...会将上下文保存在另一个线程中会导致问题-因为它还会通知主上下文(如果它与枚举同时发生) ?
如果有帮助,这是我的NSOperation子类的“ main”函数的代码(在这里我从Core Data中删除旧列表项,并通过解析XML数据来更新列表):
- (void)main {
// input the xml data into GDataXML
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:self.filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:&error];
// get the list name (so that I know which list to update)
NSString *listName;
NSArray *listNames = [doc.rootElement elementsForName:@\"listName\"];
if (listNames.count > 0) {
GDataXMLElement *listNameElement = (GDataXMLElement *) [listNames objectAtIndex:0];
listName = listNameElement.stringValue;
// NSLog(@\"listName: %@\", listName);
// perform a fetch to find the old list with the same name (if there is one)
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@\"SubListCD\" inManagedObjectContext:self.importContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@\"%K like %@\", @\"listName\", listName];
[fetchRequest setPredicate:predicate];
NSError *error;
NSArray *fetchedObjects = [self.importContext executeFetchRequest:fetchRequest error:&error];
// NSLog(@\"fetchedObjects count: %d\", [fetchedObjects count]);
[fetchRequest release];
/*
// if I found the list, update its data
*/
if ([fetchedObjects count] == 1) {
SubListCD *listToUpdate = [fetchedObjects objectAtIndex:0];
// get the list icon name
NSArray *listIconNames = [doc.rootElement elementsForName:@\"listIconName\"];
if (listIconNames.count > 0) {
GDataXMLElement *listIconNameElement = (GDataXMLElement *) [listIconNames objectAtIndex:0];
NSString *listIconName = listIconNameElement.stringValue;
// NSLog(@\"listIconName: %@\", listIconName);
listToUpdate.listIconName = [NSString stringWithString:listIconName];
}
// get the isChecklist BOOL
NSArray *isChecklistBools = [doc.rootElement elementsForName:@\"isChecklist\"];
if (isChecklistBools.count > 0) {
GDataXMLElement *isChecklistElement = (GDataXMLElement *) [isChecklistBools objectAtIndex:0];
NSString *isChecklist = isChecklistElement.stringValue;
// NSLog(@\"isChecklist: %@\", isChecklist);
listToUpdate.isCheckList = [NSNumber numberWithBool:[isChecklist isEqualToString:@\"YES\"]];
}
// get the itemsToTop BOOL
NSArray *itemsToTopBools = [doc.rootElement elementsForName:@\"itemsToTop\"];
if (itemsToTopBools.count > 0) {
GDataXMLElement *itemsToTopElement = (GDataXMLElement *) [itemsToTopBools objectAtIndex:0];
NSString *itemsToTop = itemsToTopElement.stringValue;
// NSLog(@\"itemsToTop: %@\", itemsToTop);
listToUpdate.itemsToTop = [NSNumber numberWithBool:[itemsToTop isEqualToString:@\"YES\"]];
}
// get the includeInBadgeCount BOOL
NSArray *includeInBadgeCountBools = [doc.rootElement elementsForName:@\"includeInBadgeCount\"];
if (includeInBadgeCountBools.count > 0) {
GDataXMLElement *includeInBadgeCountElement = (GDataXMLElement *) [includeInBadgeCountBools objectAtIndex:0];
NSString *includeInBadgeCount = includeInBadgeCountElement.stringValue;
// NSLog(@\"includeInBadgeCount: %@\", includeInBadgeCount);
listToUpdate.includeInBadgeCount = [NSNumber numberWithBool:[includeInBadgeCount isEqualToString:@\"YES\"]];
}
// get the list\'s creation date
NSArray *listCreatedDates = [doc.rootElement elementsForName:@\"listDateCreated\"];
if (listCreatedDates.count > 0) {
GDataXMLElement *listDateCreatedElement = (GDataXMLElement *) [listCreatedDates objectAtIndex:0];
NSString *listDateCreated = listDateCreatedElement.stringValue;
// NSLog(@\"listDateCreated: %@\", listDateCreated);
listToUpdate.dateCreated = [self dateFromString:listDateCreated];
}
// get the list\'s modification date
NSArray *listModifiedDates = [doc.rootElement elementsForName:@\"listDateModified\"];
if (listModifiedDates.count > 0) {
GDataXMLElement *listDateModifiedElement = (GDataXMLElement *) [listModifiedDates objectAtIndex:0];
NSString *listDateModified = listDateModifiedElement.stringValue;
// NSLog(@\"listDateModified: %@\", listDateModified);
listToUpdate.dateModified = [self dateFromString:listDateModified];
}
// NOTE: it\'s okay to get the displayOrder from index.plist here, since these update operations aren\'t called until after index.plist is loaded from Dropbox
// get a reference to the documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
// get the file path of the index.plist file
NSString *indexFilePath = [documentsDirectory stringByAppendingPathComponent:@\"index.plist\"];
// build an array with the names of the lists in the index
NSMutableArray *listsIndexArray = [NSMutableArray arrayWithContentsOfFile:indexFilePath];
int listIndex = [listsIndexArray indexOfObject:listName];
listToUpdate.displayOrder = [NSNumber numberWithInt:listIndex];
// remove the old list items from the listToUpdate, since I\'ll be adding them from scratch from the XML file
for (ListItemCD *item in listToUpdate.listItems) {
[self.importContext deleteObject:item];
}
// get an array of the list items so I can add them all
NSArray *listItems = [doc.rootElement elementsForName:@\"item\"];
if (listItems.count > 0) {
int counter = 0;
for (GDataXMLElement *item in listItems) {
// create the new item
ListItemCD *newItem = [NSEntityDescription insertNewObjectForEntityForName:@\"ListItemCD\" inManagedObjectContext:self.importContext];
// item name
NSArray *itemNames = [item elementsForName:@\"itemName\"];
if (itemNames.count > 0) {
GDataXMLElement *itemNameElement = (GDataXMLElement *) [itemNames objectAtIndex:0];
NSString *itemName = itemNameElement.stringValue;
// NSLog(@\"itemName: %@\", itemName);
newItem.itemName = [NSString stringWithString:itemName];
} else continue;
// item note
NSArray *itemNotes = [item elementsForName:@\"itemNote\"];
if (itemNotes.count > 0) {
GDataXMLElement *itemNoteElement = (GDataXMLElement *) [itemNotes objectAtIndex:0];
NSString *itemNote = itemNoteElement.stringValue;
// NSLog(@\"itemNote: %@\", itemNote);
newItem.itemNote = [NSString stringWithString:itemNote];
} else continue;
// itemReadOnly BOOL
NSArray *itemReadOnlyBools = [item elementsForName:@\"itemReadOnly\"];
if (itemReadOnlyBools.count > 0) {
GDataXMLElement *itemReadOnlyElement = (GDataXMLElement *) [itemReadOnlyBools objectAtIndex:0];
NSString *itemReadOnly = itemReadOnlyElement.stringValue;
// NSLog(@\"itemReadOnly: %@\", itemReadOnly);
newItem.itemReadOnly = [NSNumber numberWithBool:[itemReadOnly isEqualToString:@\"YES\"]];
} else continue;
// TODO: check my dates.. not sure if this will hold up in other locales
// item creation date
NSArray *itemCreatedDates = [item elementsForName:@\"dateCreated\"];
if (itemCreatedDates.count > 0) {
GDataXMLElement *dateCreatedElement = (GDataXMLElement *) [itemCreatedDates objectAtIndex:0];
NSString *dateCreated = dateCreatedElement.stringValue;
// NSLog(@\"dateCreated: %@\", dateCreated);
newItem.dateCreated = [self dateFromString:dateCreated];
} else continue;
// item modification date
NSArray *itemModifiedDates = [item elementsForName:@\"dateModified\"];
if (itemModifiedDates.count > 0) {
GDataXMLElement *dateModifiedElement = (GDataXMLElement *) [itemModifiedDates objectAtIndex:0];
NSString *dateModified = dateModifiedElement.stringValue;
// NSLog(@\"dateModified: %@\", dateModified);
newItem.dateModified = [self dateFromString:dateModified];
} else continue;
// item completed BOOL
NSArray *itemCompletedBools = [item elementsForName:@\"itemCompleted\"];
if (itemCompletedBools.count > 0) {
GDataXMLElement *itemCompletedElement = (GDataXMLElement *) [itemCompletedBools objectAtIndex:0];
NSString *itemCompleted = itemCompletedElement.stringValue;
// NSLog(@\"itemCompleted: %@\", itemCompleted);
newItem.itemCompleted = [NSNumber numberWithBool:[itemCompleted isEqualToString:@\"YES\"]];
} else continue;
// item completed date
NSArray *itemCompletedDates = [item elementsForName:@\"dateCompleted\"];
if (itemCompletedDates.count > 0) {
GDataXMLElement *dateCompletedElement = (GDataXMLElement *) [itemCompletedDates objectAtIndex:0];
NSString *dateCompleted = dateCompletedElement.stringValue;
// NSLog(@\"dateCompleted string: %@\", dateCompleted);
newItem.dateCompleted = [self dateFromString:dateCompleted];
// NSLog(@\"dateCompleted: %@\", newItem.dateCompleted);
} else continue;
// display order
newItem.displayOrder = [NSNumber numberWithInt:counter];
counter++;
// assign the new item to the listToUpdate
newItem.list = listToUpdate;
}
}
// the list is now imported, so set isUpdating back to NO
listToUpdate.isUpdating = [NSNumber numberWithBool:NO];
// Save the context.
NSError *saveError = nil;
if (![self.importContext save:&saveError]) {
NSLog(@\"Unresolved error %@, %@\", saveError, [saveError userInfo]);
abort();
}
else {
NSLog(@\"saved after UPDATING a list while syncing!\");
}
}
else {
NSLog(@\"UpdateOperation - couldn\'t find an old version of the list to update!: %@\", listName);
}
}
[doc release];
[xmlData release];
}
感谢您的任何建议。
没有找到相关结果
已邀请:
1 个回复
蓄荣糖些
但是我发现在处理Core Data时,“ 4”实际上并不返回副本,而通常只是另一个错误的代理。因此,我选择以这种方式复制集合: