我在上下文中创建了几个实体,用于使用
将其保存在db中AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
添加几个实体后,我执行流动提取请求
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"AppCalendarEntity"];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
它返回结果,包括我在上下文中使用第一个命令添加的实体,而不是已保存在数据库中的条目。我确保在此阶段文档状态为UIDocumentStateNormal。
当我将此行添加到已经打开的文档(UIDocumentStateNormal)时,它会返回预期的结果,即它从db获取结果以及尚未保存到db的内存上下文。
[managedDocument openWithCompletionHandler:^(BOOL success)
{
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"AppCalendarEntity"];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
}
我的问题是 1-我希望在两种情况下查询结果都相同。为什么在上述情况下并非如此。 2-对我来说,如果文档状态是UIDocumentStateNormal,我不应该在上下文中调用“openWithCompletionHandler”来打开文档。在这个特殊的场景中,它在NSFetchRequest中产生了什么不同,它在添加它之后给了我想要的结果。
如果我出错了,请告诉我
这是完整的代码
这是函数的完整代码
+ (void ) saveCalendarArrayInDbIfItAlreadyDoesNotExist : (NSArray*) appCalendarArray managedDocument: (UIManagedDocument*) managedDocument completionBlock : ( void(^) (NSArray* ObjectSavedSuccesfully, NSError *InternalError)) handler
{
// i dont know why i have to do it :( if i dont add openWithCompletionHandler my query doesnt fetch result from db rather just do query in-memory context and not db
[managedDocument openWithCompletionHandler:^(BOOL success)
{
void (^completionHandler)(NSArray* , NSError* );
completionHandler = [handler copy ];
NSError *error = nil;
NSMutableArray *array = [[NSMutableArray alloc] init];
for (id appCalendar in appCalendarArray) {
if([appCalendar isKindOfClass:[AppCalendarEntity class]])
{
AppCalendarEntity *appCalendarEntity = (AppCalendarEntity*) appCalendar;
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"MyEntity"];
requestToSeeIfCalendarWithIdExist.predicate = [NSPredicate predicateWithFormat:@"identifier = %@", appCalendarEntity.identifier];
NSError *InternalError = nil;
[requestToSeeIfCalendarWithIdExist setShouldRefreshRefetchedObjects:YES];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError] ;
// "result" is different when we encapsulate it in openWithCompletionHandler and when we don't…….MY PROBLEM
if(result == nil)
{
// return error
}
// 1 object always return that depict the in memory(context) object we created but not saved. I expect it should be zero because no object has yet been saved to database..
else if(result.count > 1)
{
[managedDocument.managedObjectContext deleteObject:appCalendar];
}
else
{
[array addObject:appCalendarEntity];
}
}
else
{
// error handling
}
}
if (error != nil)
{
completionHandler (nil, error);
return;
}
// saving all the objects
[ managedDocument updateChangeCount:UIDocumentChangeDone ];
}
答案 0 :(得分:1)
使用UIManagedDocument时,不要在MOC上调用save,因为它实现了自动保存。但是,需要告诉它应该在将来的某个时刻进行自动保存。
在该函数中摆脱对openWithCompletionHandler的调用(我知道它只是用于调试此问题)。
替换
[managedDocument.managedObjectContext save:& InternalError]
与
[managedDocument updateChangeCount:UIDocumentChangeDone];
这将通知文档现在可以保存它。
修改强>
首先,我认为你应该摆脱调试黑客攻击。你可以添加NSLog或NSAssert,但其余的东西只是让你很难说出你想要的原因,并且混淆了真正的问题。
其次,你的真正目标是什么?我可以看到方法的名称,我可以看到代码,但它们不匹配。
这里有太多“残酷”,很难理解你的问题。我将重新发布您的代码,以及删除“开放”内容的编辑,并将问题注释为代码注释。
希望这一改变能帮助您解决问题。
// First, the method name seems to indicate that some objects will be added
// to the database. however, the only database work in this method is removal.
// I don't get it.
+ (void ) saveCalendarArrayInDbIfItAlreadyDoesNotExist : (NSArray*) appCalendarArray managedDocument: (UIManagedDocument*) managedDocument
{
NSError *error = nil;
NSMutableArray *array = [[NSMutableArray alloc] init];
for (id appCalendar in appCalendarArray) {
if([appCalendar isKindOfClass:[AppCalendarEntity class]]) {
// OK, we are filtering the array of objects. We are only interested in
// objects of type AppCalendarEntity, and are going to use its identity
// property to look for objects of type MyEntity.
// What is the relationship between AppCalendarEntity and MyEntity?
AppCalendarEntity *appCalendarEntity = (AppCalendarEntity*) appCalendar;
NSFetchRequest *requestToSeeIfCalendarWithIdExist = [NSFetchRequest fetchRequestWithEntityName:@"MyEntity"];
requestToSeeIfCalendarWithIdExist.predicate = [NSPredicate predicateWithFormat:@"identifier = %@", appCalendarEntity.identifier];
NSError *InternalError = nil;
[requestToSeeIfCalendarWithIdExist setShouldRefreshRefetchedObjects:YES];
NSArray *result = [managedDocument.managedObjectContext executeFetchRequest:requestToSeeIfCalendarWithIdExist error:&InternalError];
// OK, now we just got a result from searching for a MyEntity, where
// its identifier is the same as the appCalendarEntity.
if(result == nil)
{
// return error
}
// 1 object always return that depict the in memory(context) object we created but not saved. I expect it should be zero because no object has yet been saved to database..
else if(result.count > 1)
{
// I am extremely confused by this code. First, why are you
// checking for more than 1 object? The method name indicates
// you are going to insert something. Furthermore, you are only
// deleting one object. How many do you expect? Also, why are
// you deleting an appCalendar? You were searching for a MyEntity.
// If an appCalendar is a MyEntity, then that's terrible naming.
// Furthermore, it would explain why you are finding it...
// because you create entities by inserting them in a MOC to
// begin with!
[managedDocument.managedObjectContext deleteObject:appCalendar];
}
else
{
// Even more confusion. You are adding this object to an internal
// array, not the database. Furthermore, you are doing it if there
// are either 0 or 1 MyEntity objects in the database with matching
// identifier.
[array addObject:appCalendarEntity];
}
}
}
// saving all the objects
// OK - but the only thing being saved are the ones you deleted...
[ managedDocument updateChangeCount:UIDocumentChangeDone ];
}
最后,如果我的预感是正确的,并且日历对象实际上是MyEntity对象,那么它们已经在MOC中 - 因为它们是如何创建的。当您进行提取时,您可以强制搜索忽略待处理的更改(如我之前的一条评论中所述),并且只接受保存的更改。
如果您想忽略挂起的更改,
fetchRequest.includesPendingChanges = NO;
答案 1 :(得分:0)
@Jody问题已经解决,感谢您抽出时间来解决这个问题。
首先让我解决你的困惑
1-是功能旨在保存在数据库中,它是一个有用的功能。传递给此函数的参数“appCalendarArray”由已在上下文中创建的实体组成。我有意删除了逻辑,因为它涉及与外部apis通信,解析json等等。在上下文中插入实体所需的代码已经包含在问题的第一部分中。
AppCalendarEntity *appCalendar = [AppCalendarEntity getInstanceWithManagedDocument:manageDocument];
2-我根据数据库中应该唯一的列,从已构建但尚未从上下文中保存的上下文中删除实体。如果我们已经在数据库中有对象的标识符,我们不想重新保存它。所以,我只是从上下文中删除它。此功能按预期工作,实体不会重新保存在数据库中。最后一行确实保存了上下文中留下的对象(如果有的话)。大部分时间都有很多。
3-对于错误输入抱歉AppCalendarEntity和MyEntity是相同的。
解决方案
我添加了这个标志fetchRequest.includesPendingChanges = NO; ,删除db,重新启动Xcode,它开始工作。谢谢你的坚持