- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个基于核心数据的应用程序,它具有一个对象(列表)到多个对象(列表项)的关系。我正在努力在设备之间同步数据,作为其中的一部分,我在后台线程中从 XML 文件导入列表(通过 NSOperation 子类)。
当我更新现有列表时,我删除了它所有的旧列表项(从特定于该线程的 NSManagedObjectContext 中)并用 XML 文件中的新列表项替换它们...删除是通过枚举处理的该列表的项目:
for (ListItemCD *item in listToUpdate.listItems) {
[self.importContext deleteObject:item];
}
但是,偶尔,我会在枚举期间崩溃:
* 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“* 集合 <_NSFaultingMutableSet: 0x4fcfcb0> 在枚举时发生了变异。
我不确定从哪里开始寻找该问题的原因。在进行枚举时,我不会在代码的任何其他部分修改列表。可以同时有多个线程,因为导入/更新了不同的列表......将上下文保存在另一个线程中会导致问题 - 因为它还会通知主上下文(如果它与枚举同时发生) ?
如果有帮助,下面是我的 NSOperation 子类的“主要”函数的代码(我从核心数据中删除旧列表项,并通过解析 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];
}
感谢您的任何建议。
最佳答案
错误消息中有一些线索,您可以在其中看到列出的类 NSFaultingMutableSet
。事实上,您正在枚举的集合实际上只是对多关系的代理,可能会按需加载数据。由于集合中的项目在枚举期间被标记为已删除,因此在您枚举时集合中的某些项目可能会“更改”并且您会看到该错误。
处理此问题的常用方法是创建集合的副本并枚举副本。天真的做法就是:
NSSet *iterItems = [[list.items copy] autorelease];
for (ListItemCD *item in iterItems) { ... }
但我发现在处理 Core Data 时,-copy
实际上并没有返回副本,而通常只是另一个出错的代理。所以我改为选择以这种方式复制集合:
NSSet *iterItems = [NSSet setWithSet:list.items];
for (ListItemCD *item in iterItems) { ... }
关于ios - 核心数据/NSOperation : crash while enumerating through and deleting objects,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6139989/
IO 设备如何知道属于它的内存中的值在memory mapped IO 中发生了变化? ? 例如,假设内存地址 0 专用于保存 VGA 设备的背景颜色。当我们更改 memory[0] 中的值时,VGA
我目前正在开发一个使用Facebook sdk登录(通过FBLoginView)的iOS应用。 一切正常,除了那些拥有较旧版本的facebook的人。 当他们按下“使用Facebook登录”按钮时,他
假设我有: this - is an - example - with some - dashesNSRange将使用`rangeOfString:@“-”拾取“-”的第一个实例,但是如果我只想要最后
Card.io SDK提供以下详细信息: 卡号,有效期,月份,年份,CVV和邮政编码。 如何从此SDK获取国家名称。 - (void)userDidProvideCreditCardInfo:(Car
iOS 应用程序如何从网络服务下载图片并在安装过程中将它们安装到用户的 iOS 设备上?可能吗? 最佳答案 您无法控制应用在用户设备上的安装,因此无法在安装过程中下载其他数据。 只需在安装后首次启动应
我曾经开发过一款企业版 iOS 产品,我们公司曾将其出售给大型企业,供他们的员工使用。 该应用程序通过 AppStore 提供,企业用户获得了公司特定的配置文件(包含应用程序配置文件)以启用他们有权使
我正在尝试将 Card.io SDK 集成到我的 iOS 应用程序中。我想为 CardIO ui 做一个简单的本地化,如更改取消按钮标题或“在此保留信用卡”提示文本。 我在 github 上找到了这个
我正在使用 CardIOView 和 CardIOViewDelegate 类,没有可以设置为 YES 的 BOOL 来扫描 collectCardholderName。我可以看到它在 CardIOP
我有一个集成了通话工具包的 voip 应用程序。每次我从我的 voip 应用程序调用时,都会在 native 电话应用程序中创建一个新的最近通话记录。我在 voip 应用程序中也有自定义联系人(电话应
iOS 应用程序如何知道应用程序打开时屏幕上是否已经有键盘?应用程序运行后,它可以接收键盘显示/隐藏通知。但是,如果应用程序在分屏模式下作为辅助应用程序打开,而主应用程序已经显示键盘,则辅助应用程序不
我在模拟器中收到以下错误: ImageIO: CGImageReadSessionGetCachedImageBlockData *** CGImageReadSessionGetCachedIm
如 Apple 文档所示,可以通过 EAAccessory Framework 与经过认证的配件(由 Apple 认证)进行通信。但是我有点困惑,因为一些帖子告诉我它也可以通过 CoreBluetoo
尽管现在的调试器已经很不错了,但有时找出应用程序中正在发生的事情的最好方法仍然是古老的 NSLog。当您连接到计算机时,这样做很容易; Xcode 会帮助弹出日志查看器面板,然后就可以了。当您不在办公
在我的 iOS 应用程序中,我定义了一些兴趣点。其中一些有一个 Kontakt.io 信标的名称,它绑定(bind)到一个特定的 PoI(我的意思是通常贴在信标标签上的名称)。现在我想在附近发现信标,
我正在为警报提示创建一个 trigger.io 插件。尝试从警报提示返回数据。这是我的代码: // Prompt + (void)show_prompt:(ForgeTask*)task{
您好,我是 Apple iOS 的新手。我阅读并搜索了很多关于推送通知的文章,但我没有发现任何关于 APNS 从 io4 到 ios 6 的新更新的信息。任何人都可以向我提供 APNS 如何在 ios
UITabBar 的高度似乎在 iOS 7 和 8/9/10/11 之间发生了变化。我发布这个问题是为了让其他人轻松找到答案。 那么:在 iPhone 和 iPad 上的 iOS 8/9/10/11
我想我可以针对不同的 iOS 版本使用不同的 Storyboard。 由于 UI 的差异,我将创建下一个 Storyboard: Main_iPhone.storyboard Main_iPad.st
我正在写一些东西,我将使用设备的 iTunes 库中的一部分音轨来覆盖 2 个视频的组合,例如: AVMutableComposition* mixComposition = [[AVMutableC
我创建了一个简单的 iOS 程序,可以顺利编译并在 iPad 模拟器上运行良好。当我告诉 XCode 4 使用我连接的 iPad 设备时,无法编译相同的程序。问题似乎是当我尝试使用附加的 iPad 时
我是一名优秀的程序员,十分优秀!