我的应用程序有时会将对象插入到托管对象上下文中,而这些对象并不一定要保存.例如,当我启动"添加实体"模式时,我创建了一个托管对象并将其分配给模态.如果用户从该模态中保存,我将保存上下文.如果他取消,我删除该对象,不需要保存.
我现在已经引入了一个"导入"功能,切换到我的应用程序(使用URL方案)并添加一个实体.由于其中一个模态可能是打开的,因此此时保存上下文是不安全的.即使用户取消,也会保存为模态创建的瞬态对象,并且无法保证稍后将保存删除(来自取消操作) - 用户可能会退出该应用程序.
同样,每当我的应用程序退出时,我都无法保存.如果模式在该点处打开,则将错误地保存临时对象.
为了解决这个问题,我试图用一个孩子背景下,作为讨论在这里.阅读了所有我能在SO上找到的东西,我会有几个问题:
我应该为每个上下文使用哪种并发类型?请记住,我没有这样做是为了获得性能/线程优势.我知道如果要有子上下文,我不能使用NSConfinementConcurrencyType作为主上下文,但我不确定其他两个选项中哪一个最适合.对于子上下文,它是否需要匹配?或者我甚至可以在这里使用限制类型?我尝试了各种各样的组合,似乎一切正常,但我想知道哪个适合我的要求.
(附带问题)如果我使用iVar类,为什么我才能让它工作?我以为我应该能够在创建它的方法中声明临时上下文,然后使用entity.managedObjectContext来引用它.但是当我访问它时它似乎是零?如果我改为使用iVar来保存引用,则会对此进行纠正.
什么是正确的方法或将更改传播到主要上下文?我已经在每个上下文中看到了使用不同的块包装实现的各种注释.它取决于我的并发类型吗?我目前的版本是:
//save the new entity in the temporary context
NSError *error = nil;
if (![myObject.managedObjectContext save:&error]) {NSLog(@"Error - unable to save new object in its (temporary) context");}
//propogate the save to the main context
[self.mainContext performBlock:^{
NSError *error2 = nil;
if (![self.mainContext save:&error2]) {NSLog(@"Error - unable to merge new entity into main context");}
}];
Run Code Online (Sandbox Code Playgroud)当我的用户保存时,它会向其委托(我的主视图控制器)发送一条消息.委托传递添加的对象,它必须在主上下文中找到相同的对象.但是当我在主要环境中寻找它时,却找不到它.主要上下文确实包含实体 - 我可以记录它的详细信息并确认它在那里 - 但地址是不同的?如果这意味着发生(为什么?),如何在保存后在主上下文中找到添加的对象?
感谢您的任何见解.很抱歉有一个很长的,多部分的问题,但我认为有人可能已经解决过所有这些问题.
我正在创建一个允许我使用Core Data的框架.在框架的测试目标中,我已经配置了一个名为的数据模型MockModel.xcdatamodeld.它包含一个名为MockManaged具有单个Date属性的实体.
所以我可以测试我的逻辑,我正在创建一个内存存储.当我想验证我的保存逻辑时,我创建了一个内存存储的实例并使用它.但是,我一直在控制台中获得以下输出:
2018-08-14 20:35:45.340157-0400 xctest[7529:822360] [error] warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'LocalPersistenceTests.MockManaged' so +entity is unable to disambiguate.
CoreData: warning: Multiple NSEntityDescriptions claim the NSManagedObject subclass 'LocalPersistenceTests.MockManaged' so +entity is unable to disambiguate.
2018-08-14 20:35:45.340558-0400 xctest[7529:822360] [error] warning: 'MockManaged' (0x7f986861cae0) from NSManagedObjectModel (0x7f9868604090) claims 'LocalPersistenceTests.MockManaged'.
CoreData: warning: 'MockManaged' (0x7f986861cae0) from NSManagedObjectModel (0x7f9868604090) claims 'LocalPersistenceTests.MockManaged'.
2018-08-14 20:35:45.340667-0400 xctest[7529:822360] [error] warning: 'MockManaged' (0x7f986acc4d10) from NSManagedObjectModel (0x7f9868418ee0) claims 'LocalPersistenceTests.MockManaged'.
CoreData: warning: 'MockManaged' (0x7f986acc4d10) from …Run Code Online (Sandbox Code Playgroud) 我有一个带谓词的fetchedResultsController,其中"isOpen == YES"
在调用closeCurrentClockSet时,我将该属性设置为NO.因此,它应该不再出现在我的tableView上.
出于某种原因,这种情况并没有发生.
有人可以帮我解决这个问题吗?
-(void)closeCurrentClockSet
{
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"isOpen == YES"];
NSArray *fetchedObjects =
[self fetchRequestForEntity:@"ClockSet"
withPredicate:predicate
inManagedObjectContext:[myAppDelegate managedObjectContext]];
ClockSet *currentClockSet = (ClockSet *)fetchedObjects.lastObject;
[currentClockSet setIsOpen:[NSNumber numberWithBool:NO]];
}
Run Code Online (Sandbox Code Playgroud)
-
通过调用自定义fetchRequestForEntity:withPredicate:inManagedObjectContext方法,我有更多方法,使用完全相同的方法.
在这些方法中,更改属性时,tableView会正确更新!但是这一个上面(closeCurrentClockSet),没有!我无法弄清楚为什么.
-
我对fetchedResultsController的实现来自Apple的文档.
另外,另一个细节.如果我将我的应用程序发送到后台.关闭它并重新打开,tableView显示更新应该!
我尽力在stackOverflow上关注之前的问题.没运气.我也NSLogged这个骨头.正确获取对象.这是正确的.isOpen属性正在更新为NO.但由于某种原因,我的fetchedResultsController不更新tableView.
我确实尝试过几个"锤子"解决方案,比如reloadData和调用performFetch.但那没用.或者使用它们会有意义......
编辑:抓住它,DID工作,在我的resultsController上的performFetch之后调用reloadData imediatly但是使用reloadData正在敲定一个解决方案.此外,它还会取消所有动画.我希望我的控制器自动更新我的tableView.
有人可以帮我解决这个问题吗?
任何帮助是极大的赞赏!
谢谢,
努诺
编辑:
完整的实施.
fetchedResultsController非常标准和简单.其他一切都来自Apple的文档
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController) {
return _fetchedResultsController;
} …Run Code Online (Sandbox Code Playgroud) objective-c nsfetchedresultscontroller nsmanagedobject nsmanagedobjectcontext ios
我正在使用Swift中的Core Data Stack - Demystified,但是当我到达线路时
self.context = NSManagedObjectContext()
Run Code Online (Sandbox Code Playgroud)
我收到了警告
`init()` was deprecated in iOS 9.0: Use -initWithConcurrencyType: instead
Run Code Online (Sandbox Code Playgroud)
我看到我可以做以下其中一项了 self.context =
NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.ConfinementConcurrencyType)
NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
Run Code Online (Sandbox Code Playgroud)
但是ConfinementConcurrencyType现在也被弃用了,这让我MainQueueConcurrencyType和PrivateQueueConcurrencyType.这两者有什么区别,我应该如何选择使用哪一个?我阅读了这份文档,但我并不理解.
我正在NSManagedObjectContext私有队列中创建一个处理来自文件和/或服务的数据更新:
NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
privateContext.persistentStoreCoordinator = appDelegate.persistentStoreCoordinator;
Run Code Online (Sandbox Code Playgroud)
由于我使用的是私有队列,我不完全理解performBlock:和performBlockAndWait:方法之间的区别......为了执行我的数据更新,我目前正在这样做:
[privateContext performBlock: ^{
// Parse files and/or call services and parse
// their responses
// Save context
[privateContext save:nil];
dispatch_async(dispatch_get_main_queue(), ^{
// Notify update to user
});
}];
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我的数据更新是同步和顺序进行的,所以我认为这是保存上下文的正确位置,对吧?如果我做错了什么,如果你告诉我,我会很感激.另一方面,这段代码是否相同?:
[privateContext performBlockAndWait: ^{
// Parse files and/or call services and parse
// their responses
// Save context
[privateContext save:nil];
}];
// Notify update to user
Run Code Online (Sandbox Code Playgroud)
我想这是保存上下文的正确位置......这两种方法之间有什么区别(如果有的话,在这种情况下)?
如果不是执行同步服务调用或文件解析,我需要执行异步服务调用怎么办?如何管理这些数据更新?
提前致谢
synchronization asynchronous core-data nsmanagedobjectcontext ios
我的Cocoa/Application在主线程上有一个托管对象上下文.当我需要更新我的数据时,我的程序将:
这是在主线程上接收通知的函数
- (void)loadManagedObjectFromNotification:(NSNotification *)saveNotification
{
if ([NSThread isMainThread]) {
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
} else {
[self performSelectorOnMainThread:@selector(loadManagedObjectFromNotification:) withObject:saveNotification waitUntilDone:YES];
}
}
Run Code Online (Sandbox Code Playgroud)
我没有收到任何错误.我的问题是合并结果,它实际上连接了两个上下文中的Managed Objects.
我的实体是一个非常简单的属性和关系列表.
也许合并需要一些指令,以便了解更新的托管对象何时不是新的,而是第一个的编辑版本.我想在某个地方我需要指定一种方式来单义地识别实体,(例如,属性可以像ID一样)和类似合并策略的东西(如果2个被管理对象代表同一个对象,请使用lastModificationDate更多)最近).
我只需要了解如何正确合并2个上下文,以便为每个对象创建一个更新的副本.
这个问题现在对我来说很清楚了.2上下文有很大的不同:ObjectID.当主线程上的上下文使用持久存储协调器获取ManagedObjects时,第二个线程通过获取远程URL来创建这些对象.即使对象具有相同的内容,它们也将具有2个不同的objectID.
我的对象已经有一个唯一的标识符,我可以使用setObjectId来设置这个值.(Apple文档说这不是一个好主意).
cocoa core-data objective-c nsmanagedobject nsmanagedobjectcontext
我有一个NSFetchedResultsController和几个操作更新托管对象在不同的线程上通过NSOperationQueue.
FRC(带有谓词)看起来像这样:
- (NSFetchedResultsController*)fetchedResultsController
{
if(fetchedResultsController) return fetchedResultsController;
NSManagedObjectContext* mainContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"Check" inManagedObjectContext:mainContext]];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"isSync == %@", [NSNumber numberWithBool:NO]]];
[fetchRequest setFetchBatchSize:10];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
fetchedResultsController.delegate = self;
[fetchRequest release], fetchRequest = nil;
return fetchedResultsController;
}
Run Code Online (Sandbox Code Playgroud)
主线程和线程操作具有自己的托管对象上下文.他们只共享同一个协调员.
在线程操作中,我将isSync属性从更改NO为YES.要知道Check要更新的实体是什么,主要上下文将传递给线程化的a NSManagedObjectID.线程操作检索托管对象,如下所示:
-(void)main
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSManagedObjectContext *exportContext = [[NSManagedObjectContext alloc] …Run Code Online (Sandbox Code Playgroud) core-data nsfetchedresultscontroller nsoperationqueue nsmanagedobjectcontext ios
我有两个托管对象上下文共享同一个持久性存储协调器:
NSMainQueueConcurrencyType用于主线程和NSPrivateQueueConcurrencyType用于进行后台处理的.所有数据解析工作都在针对私有队列的performBlock调用中进行,并通过NSManagedObjectContextDidSaveNotification主要线程上的UI更新进行合并.
我启用了Core Data多线程断言,并且在崩溃发生时它们永远不会触发.
我偶尔会遇到一个崩溃,statement is still active当我推送一个有一段NSFetchedResultsController时间背景上下文工作的新视图时.崩溃将触发对获取的结果控制器的获取或在存储数据的代码中.当它在数据解析部分崩溃时,它总是以多对多关系失败.
到目前为止,这些崩溃是100%的iOS 8,我从未在7上看过它们.
我的问题是这样的:假设我没有违反线程限制(断言应该大声喊叫,而且还没有...)是否有任何其他显而易见的事情我可能会这样做会导致主线程上下文爆炸后台线程正在处理持久存储的工作?
这就是Crashlytics所说的:
Thread : Fatal Exception: NSInternalInconsistencyException
0 CoreFoundation 0x00000001871e659c __exceptionPreprocess + 132
1 libobjc.A.dylib 0x00000001978f00e4 objc_exception_throw + 60
2 CoreData 0x0000000186e97c6c -[NSSQLiteStatement cachedSQLiteStatement]
3 CoreData 0x0000000186e9739c -[NSSQLiteConnection prepareSQLStatement:] + 76
4 CoreData 0x0000000186eb3810 -[NSSQLChannel selectRowsWithCachedStatement:] + 76
5 CoreData 0x0000000186f9e7a4 newFetchedRowsForFetchPlan_MT + 1100
6 CoreData 0x0000000186ecf948 -[NSSQLCore newFetchedPKsForSourceID:andRelationship:] + 2120
7 CoreData 0x0000000186ecea24 -[NSSQLCore newValueForRelationship:forObjectWithID:withContext:error:] + …Run Code Online (Sandbox Code Playgroud) 文件说:
Run Code Online (Sandbox Code Playgroud)- (void)reset将接收器返回到其基本状态.
讨论
所有接收方的托管对象都被"遗忘".如果使用此方法,则应确保还丢弃对使用接收方获取的任何托管对象的引用,因为它们之后将无效.
Run Code Online (Sandbox Code Playgroud)- (void)rollback从撤消堆栈中删除所有内容,放弃所有插入和删除,并将更新的对象还原为其上次提交的值.
讨论
此方法不会从持久性存储库中重新获取数据.
似乎在我对我的上下文做了一些更改之后,调用这两个方法将完全相同:丢弃更改并将更新的对象恢复为其上次提交的值.那-reset实际上做了什么?
最近我开始知道"你真的不应该调用AppDelegate来获取托管对象上下文".苹果公司也已经把这个建议到他们的文档在这里.它是这样的:
视图控制器通常不应从全局对象(例如应用程序委托)检索上下文 - 这会使应用程序体系结构变得僵硬.视图控制器也不应为自己的用途创建上下文(除非它是嵌套的上下文).这可能意味着使用控制器上下文执行的操作未在其他上下文中注册,因此不同的视图控制器将对数据具有不同的视角.
此外,他们还提到了其他一些获取背景的方法.到目前为止,我无法弄清楚他们在那里想说些什么.任何人都可以对这个问题有所了解.任何支持语句的代码片段都是最受欢迎的.
编辑
但是,有时从应用程序或文档或视图控制器以外的其他位置检索上下文更容易或更合适.您可能在基于Core Data的应用程序中使用的几个对象保留对托管对象上下文的引用.托管对象本身具有对其自身上下文的引用,支持Core Data的各种控制器对象(如阵列和对象控制器)(OS X中的NSArrayController和NSObjectController以及iOS中的NSFetchedResultsController)也是如此.
从其中一个对象中检索上下文的优点是,如果重新构建应用程序,例如使用多个上下文,则代码可能仍然有效.例如,如果您有一个托管对象,并且想要创建与其相关的新托管对象,则可以向原始对象询问其托管对象上下文并使用该对象创建新对象.这将确保您创建的新对象与原始对象位于相同的上下文中.
究竟是什么?我确定它与下面的Highly投票答案不相似.有人可以帮我理解这部分Apple文档吗?
core-data objective-c nsmanagedobjectcontext ios appdelegate