我一直在来自managedObjectContext上的save:命令崩溃.它甚至不满足NSLog语句,所以我没有看到未解决的错误语句,所以我无法弄清楚问题可能是什么.它不是每次都会发生,而只是偶尔发生.
这是代码(基本上想要增加一个计数器):
if ([[managedObject valueForKey:@"canSee"]boolValue]){
int read = [[managedObject valueForKey:@"timesRead"] intValue] +1;
[managedObject setValue:[NSNumber numberWithInt:read] forKey:@"timesRead"];
NSError *error;
if (![resultsController.managedObjectContext save:&error]) { //<-- crashes on this line!
NSLog(@"Unresolved Core Data Save error %@, %@", error, [error userInfo]);
exit(-1);
}
Run Code Online (Sandbox Code Playgroud)
在控制台窗口中,我收到如下消息:
2010-08-20 08:12:20.594 AppName[23501:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet controllerWillChangeContent:]: unrecognized selector sent to instance 0xe54f560'
Run Code Online (Sandbox Code Playgroud)
或这个:
2010-08-20 08:12:20.594 AppName[23501:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet controllerWillChangeContent:]: unrecognized selector sent to instance …Run Code Online (Sandbox Code Playgroud) 我正在研究一个核心数据应用程序,它具有相当大的托管对象层次结构,类似于树.
创建基础对象时,它会创建一些子对象,这些子对象又创建自己的子对象,依此类推.这些子对象中的每一个都可以使用NSURLConnections收集信息.
现在,我想在managedObjectContext中使用undoManager支持undo/redo.问题是,如果用户创建基础对象,然后尝试撤消该操作,则不会删除基础对象.相反,可以移除一个或多个子对象.显然,这种行为是不可预测的,也是不受欢迎的.
所以我尝试默认禁用撤消注册.我通过disableUndoRegistration:在managedObjectContext中修改任何内容之前调用来完成此操作.然后,在基本操作(例如创建基础对象)之前启用撤销注册,再次重新禁用后续注册.
现在,当我尝试撤消时,我收到此错误:
undo:NSUndoManager 0x1026428b0处于无效状态,使用过多的嵌套撤销组调用undo
思考?
cocoa core-data nsundomanager nsmanagedobject nsmanagedobjectcontext
mainMOC 是主要的托管对象上下文
editorMOC是editorViewController使用撤消管理器创建的托管对象上下文,因此用户可以编辑单个托管对象
editorMOC保存后,mainMOC刷新通知处理程序中的更新的托管对象NSManagedObjectContextDidSaveNotification
在保存处理程序中,如果我使用[mainMOC refreshObject:obj mergeChanges:YES]对象的更新,则不会在mainMOC后刷新中反映出来.如果我使用[mainMOC refreshObject:obj mergeChanges:NO]该对象失效,并且在下一个故障时,更改将反映在从商店加载的数据中.
问题:为什么对象在mergeChanges:YES指定时不反映更新?
我有一个基于核心数据的应用程序,具有多个托管对象上下文.该应用程序是复杂和专有的,所以我不能直接从应用程序共享代码.我创建了一个简单的测试应用程序,试图重现我的问题,但测试应用程序没有出现问题.我无法在实现之间找到逻辑差异.我为没有发布示例代码而道歉,我相信我在下面解释了实现.如果问题不明确,请在评论中提问,我会尽力澄清.
这是我的情况.下面描述的所有内容都在主线程上运行.
该应用程序有一个主要的托管对象上下文mainMOC,在主线程上访问,用于NSFetchedResultsControllers在各种表视图中显示数据.
我有一个调用的视图控制器EditorViewController,允许编辑特定实体的现有对象.此视图控制器editorMOC使用具有撤消管理器的相同持久性存储协调器创建自己的托管对象上下文,以便在解除编辑器时可以回滚或保存更改.
EditorViewController正在观察NSManagedObjectContextDidSaveNotification.发生此通知时,通知处理程序调用[_mainMOC mergeChangesFromContextDidSaveNotification:notification]以将更改合并editorMOC到mainMOC.
使用a的表视图控制器NSFetchedResultsController正在处理控制器委托消息.
我已经添加了NSLog输出来查看上述所有步骤中发生的情况,并且我已经验证了以下内容:
NSManagedObjectContextDidSaveNotification被调用并且包含更新的对象.controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:协议消息.mainMOC并没有反映更新,并且更新的对象没有被无效mergeChangesFromContextDidSaveNotification:.作为参考,我的主应用程序和测试应用程序都实现了上述功能,但测试应用程序显示正确合并的更新,主应用程序没有.
我正在寻找关于什么会导致mergeChangesFromContextDidSaveNotification:不能成功合并和/或使更新的对象无效的建议.
谢谢!
我的程序确实像以下链接一样工作:
更新NSFetchedResultsController的结果而不进行新的提取
从Apple的Core Data项目复制NSFetchedResultsControllerDelegate的实现,我的谓词是:
[NSPredicate predicateWithFormat:@"isMyTest == TRUE"]
Run Code Online (Sandbox Code Playgroud)
如果属性更新从TRUE变为FALSE,则会从tableview中删除行(因为该行的对象fetchedObjects位于NSFetchedResultsController中)
但是,如果属性更新从FALSE变为TRUE,则NSFetchedResultsController不会通知任何内容,因此在表视图中无法看到新数据.如果我手动更新BOTH NSFetchedResulsController和UITableView,它会显示新数据.
我以为NSFetchedResultController监视持久存储中的所有变化,是不是太大了希望?:d
(我真的想这样做,因为其他视图控制器可以更新持久存储,然后很难更新视图控制器.)
如果是这样,你能让我知道如何以优美的方式更新NSFetchedResultsController?
(更新)
在NSfetchedResultsController的引用中,我读了下面的单词:
因此,控制器有效地具有三种操作模式,由它是否具有委托以及是否设置了缓存文件名来确定.
无跟踪:委托设置为nil.控制器只是提供对执行提取时的数据的访问.
仅内存跟踪:委托是非零的,文件缓存名称设置为nil.控制器监视其结果集中的对象并更新部分和订购信息以响应相关变化.
完全持久跟踪:委托和文件缓存名称是非零的.控制器监视其结果集中的对象并更新部分和订购信息以响应相关变化.控制器维护其计算结果的持久高速缓存.
"完全持久跟踪"并不意味着我想要什么?我设置了cacheName,但它的工作原理相同.
core-data nsnotifications nsfetchedresultscontroller nsmanagedobjectcontext ios
我正在学习CoreData.显然,你所包含的主要类之一是NSManagedObjectContext.我不清楚这个的确切作用.从我读过的文章中,您似乎可以拥有多个NSManagedObjectContexts.这是否意味着NSManagedObjectContext基本上是后端的副本?
当存在多个不同的副本时,如何将其解析为一致的后端?
所以,基本上有两个问题:
NSManagedContext是后端数据库的副本吗?
和...
例如,假设我在上下文A中进行了更改,并在上下文B中进行了一些其他更改.然后我先调用保存在A上,然后是B?B会占上风吗?
谢谢
cocoa-touch core-data objective-c nsmanagedobjectcontext ios
我正在构建我的第一个iOS应用程序,理论上应该非常简单,但我很难让它足够防弹,让我有信心将它提交到App Store.
简而言之,主屏幕具有表格视图,在选择行时,它将分段到另一个表格视图,该表格视图以主 - 细节方式显示与所选行相关的信息.基础数据每天从Web服务检索为JSON数据,然后缓存在Core Data存储中.删除当天之前的数据以阻止SQLite数据库文件无限增长.所有数据持久性操作都使用Core Data执行,并具有NSFetchedResultsController详细信息表视图的基础.
我看到的问题是,如果你在主屏幕和细节屏幕之间快速切换几次,同时检索,解析和保存新数据,应用程序会冻结或完全崩溃.似乎存在某种竞争条件,可能是由于Core Data在后台导入数据而主线程正在尝试执行获取,但我猜测.我在捕获任何有意义的崩溃信息时遇到了麻烦,通常它是Core Data堆栈中的一个SIGSEGV.
下表显示加载详细信息表视图控制器时发生的事件的实际顺序:
Main Thread Background Thread
viewDidLoad
Get JSON data (using AFNetworking)
Create child NSManagedObjectContext (MOC)
Parse JSON data
Insert managed objects in child MOC
Save child MOC
Post import completion notification
Receive import completion notification
Save parent MOC
Perform fetch and reload table view
Delete old managed objects in child MOC
Save child MOC
Post deletion completion notification
Receive deletion completion notification
Save parent MOC
在JSON数据到达时触发AFNetworking完成块后,将NSManagedObjectContext创建嵌套并传递给"导入器"对象,该对象解析JSON数据并将对象保存到Core …
在我的应用程序中,我能够清除数据库中的所有数据.完成此操作后,将解析捆绑的JSON,然后将其保存到数据库(以便将数据库返回到默认状态).解析和保存此JSON的操作在任何情况下都可以正常工作,除非在清除并重新创建持久性存储之后,在这种情况下我得到'NSInvalidArgumentException',原因:'无法从此NSManagedObjectContext的协调器访问对象的持久存储'.在保存在后台上下文中后尝试在主线程上下文中调用mergeChangesFromContextDidSaveNotification时抛出此异常.
重新创建存储是在主线程上执行的,因为解析和保存总是在后台线程上进行.这是我的托管对象上下文的getter,以确保线程安全:
- (NSManagedObjectContext *)managedObjectContext {
NSMutableDictionary *threadDictionary = [[NSThread currentThread] threadDictionary];
NSManagedObjectContext *threadContext = threadDictionary[ckCoreDataThreadKey];
if (!threadContext) {
threadContext = [self newManagedObjectContext];
threadDictionary[ckCoreDataThreadKey] = threadContext;
}
return threadContext;
}
Run Code Online (Sandbox Code Playgroud)
newManagedObjectContext方法为所有新实例提供相同的NSPersistentStoreCoordinator对象.
以下是用于清除存储的代码(始终在主线程上执行):
[self.managedObjectContext lock];
[self.managedObjectContext reset]; //to drop pending changes
//delete the store from the current managedObjectContext
if ([[self.managedObjectContext persistentStoreCoordinator] removePersistentStore:[[[self.managedObjectContext persistentStoreCoordinator] persistentStores] lastObject] error:error]) {
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:error];
[[self.managedObjectContext persistentStoreCoordinator] addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:error]; //recreates the persistent store
[self addSkipBackupAttributeToItemAtURL:storeURL];
}
[self.managedObjectContext unlock];
Run Code Online (Sandbox Code Playgroud)
奇怪的是,这个相同的代码在其他项目中运行良好,除了数据内容之外没有其他区别.任何帮助是极大的赞赏!
在托管对象中,我已经存储了应用程序容器中图像文件的路径.
删除托管对象后,应将图像文件移至废纸篓.这应该尽可能晚地完成,以便我可以尽可能长时间地提供撤消功能.
我正在按照这个问题的答案:如何在删除Core Data对象时处理外部数据的清理,并在我的托管对象子类中重写-didSave以废弃文件.
事实证明,这仅适用于:
但是,在以下情况中,未在托管对象中调用-isSaved:
我理解为什么会这样.由于删除的对象从未在第一个地方持久存在,因此在删除后不会保存它,也不会调用-didSave.
现在我正在寻找另一个将引用文件移动到垃圾箱的地方.那可能在哪里?
我有两个NSManagedObjectContext名字importContext和childContext.childContext是他们的孩子importContext,他们俩都是NSPrivateQueueConcurrencyType.
为了避开主线程,我正在对importContext队列进行大量工作.这项工作涉及大量取的并保存,所以它的方便来包装整个事情里面performBlockAndWait:的importContext(它不会被同步操作需要,因为我以后有代码performBlockAndWait依赖于它的结果).
在这项工作中的某些时候,我可能需要从JSON结果创建新的托管对象.这些JSON值可能无效并且我的验证失败,因此在创建对象后,如果它们不好,我需要能够抛弃它们.这就是childContext进来的地方.我将新对象插入其中,如果它的JSON属性最终没有意义,我就放弃了childContext.
当我需要保存时,问题就来了childContext.我希望它有自己的私有队列,与父队列分开.但是,这会导致iOS 7(不是iOS 8)上的死锁.当我在iOS 8模拟器和设备上运行相同的代码时,childContext它会在单独的线程上创建自己的队列并正确进行保存.
看起来当我运行iOS 7时,它childContext正在尝试save:在父队列中进行,但是父进程正在等待其子进程导致死锁.在iOS 8中,这不会发生.有谁知道为什么?
这是简化的代码:
-(NSManagedObjectContext *)importContext
{
NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.persistentStoreCoordinator = [self storeCoordinator];
return moc;
}
-(void)updateItems:(NSArray*)ItemDescriptions
{
[self.importContext performBlockAndWait:^{
//get info and update
...
...
if(needToCreateNewItem){
NSManagedObjectContext* childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childContext.parentContext = …Run Code Online (Sandbox Code Playgroud) 直接从NSManagedObjectContext 文档中我对以下段落感到困惑:
基于队列的托管对象上下文的Setter方法是线程安全的.您可以直接在任何线程上调用这些方法.
最大的问题是ManagedObjectContext上的setters方法,但不是在这个上下文拥有的ManagedObjects中?还是两者兼而有之?特别是如果对于私有队列MOC对象是这样的:
[privateContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
Run Code Online (Sandbox Code Playgroud)
无论线程执行此行,都是线程安全的,但是会像:
[myPrivateQueueOwnedManagedObject setTitle:@"My Title];
Run Code Online (Sandbox Code Playgroud)
也是线程安全吗?文档对此真的很模糊,但我的理解是,这不是线程安全是正确的吗?
在ManagedObjectContext中获取属性的getter如请求persistentStoreCoordinator属性会是线程安全的吗?我的理解是它不会.
另外,我一直认为某些托管对象属性(如objectID)是线程安全的,不需要使用performBlock:或performBlockAndWait进行访问:托管对象上是否存在线程安全的其他任何属性?