NSFetchRequest 没有看到 NSManagedObjectContext 中关系的变化

Posted

技术标签:

【中文标题】NSFetchRequest 没有看到 NSManagedObjectContext 中关系的变化【英文标题】:NSFetchRequest not seeing changes to relationships in NSManagedObjectContext 【发布时间】:2012-04-11 22:35:41 【问题描述】:

我将 UIManagedDocument 用于核心数据。我的 managedObjectContext 中有日历对象,它们具有 calendarSelected 属性。 Calendar 实体与 CalendarEntry 具有一对多关系。

当我更改他们的calendarSelected 属性,然后执行 NSFetchRequest 以使用以下谓词获取 CalendarEntry 对象时:

[NSPredicate predicateWithFormat:@"calendar.calendarSelected = YES"]

calendar.calendarSelected 似乎没有看到我在没有我调用的情况下所做的更改

[myManagedDocument saveToURL:myManagedDocument.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) ];

首先。我在某处读到,即使更改尚未写入持久存储,从同一上下文中获取内容也应该尊重在该上下文中所做的更改。我错过了什么?

更新:

当 calendarEvents 关系出现故障时,它似乎正在发生:calendarEvents = "<relationship fault: 0x91aec90 'calendarEvents'>"; 但在关系没有故障时工作。

【问题讨论】:

所有更改都会发生这种情况还是只是新的更改? 我不确定。我会试着找出答案。有关更多信息,请参阅我的编辑。 【参考方案1】:

如果问题仅出现在由一对多关系指向的新插入的 CalendarEntry 对象上,那么它们可能还没有永久对象 ID。这很容易调试,只需转储对象 ID 并检查它是临时的还是永久的。

我已经看到当保留多对关系中的包含对象时会发生这种情况;似乎只要保留它,关系中的多对包含对象就永远不会达到它们获得永久ID的程度。通过将应用程序置于后台并重新启动它有点容易调试;后台处理通常会强制 UIManagedDocument 进行保存,此后一切都会按您的预期开始工作,因为 CalendarEntry 实体将被分配永久 ID,因此将变得可获取。

就保存 UIManagedDocument 而言,在使用 UIManagedDocument 时,您无法控制何时会发生这种情况。最好的办法是通过 updateChangeCount:UIDocumentChangeDone 安排将来发生的保存,但同样,它会“很快”发生,但不是确定性的,即不可能知道它何时会发生。

要解决临时对象 ID 与永久对象 ID 的问题,如果您遇到这种情况,请在 NSManagedObjectContext 上尝试以下类别;在您完成插入新的 CalendarEntry 对象后调用它,以强制执行此问题。

// Obtain permanent ids for any objects that have been inserted into
// this context.
//
// As of this writing (ios 5.1), we need to manually obtain permanent
// ids for any inserted objects prior to a save being performed, or any
// objects that are currently retained, that have relationships to the
// inserted objects, won't be updated with permanent ids for the related
// objects when a save is performed unless the retained object is refetched.
// For many objects, that will never occur, so we need to force the issue.

- (BOOL)obtainPermanentIDsForInsertedObjects:(NSError **)error

    NSSet * inserts = [self insertedObjects];

    if ([inserts count] == 0) return YES;

    return  [self obtainPermanentIDsForObjects:[inserts allObjects]
                                         error:error];

【讨论】:

【参考方案2】:

基本上,在进行任何更改后,您必须要么使用撤消管理器,要么调用 [document updateChangeCount:UIDocumentChangeDone];就这样!任何其他“保存”调用只会在某处破坏其他内容。

规范的更新方法应该是……

你知道你在主线程上

NSManagedObjectContext *ctx = document.managedObjectContext;
// Do stuff with it
[document updateChangeCount:UIDocumentChangeDone];

你在不同的线程上

[document.managedObjectContext performBlock:^
    // Do stuff with it on the main thread
    [document updateChangeCount:UIDocumentChangeDone];
];

NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.parentContext = document.managedObjectContext;
[moc performBlock:^
    // Do stuff with it on a background thread
    // Push changes up to parent (which is the document's main MOC)
    // The document will know it's dirty and save changes
    [moc save:&error];
];

或者,如果您想在后台线程中进行更改,而不会弄乱主文档 MOC,请在父文档中进行...主 MOC 将在下一次提取之前看到它们。

[document.parentContext.managedObjectContext performBlock:^
    // Do stuff with it on a background thread, but the main MOC does not
    // see the changes until it does a fetch.
];

【讨论】:

嗯。这不是我想听到的答案。我已经发现保存文档可以解决问题,但保存文档并不便宜,我宁愿不必这样做。不过恐怕你是对的。 如果您只是在更改后执行此操作... 有帮助吗? [文档 updateChangeCount:UIDocumentChangeDone];另外,您是否在不同的线程中进行更改? 只是在做 [document updateChangeCount:UIDocumentChangeDone];似乎没有帮助。 我能够修改我正在做的事情以获取所有选定的日历(有效),然后通过执行“WHERE calendar.unique = OR calendar. unique = ..." 蹩脚,但它似乎正在工作。

以上是关于NSFetchRequest 没有看到 NSManagedObjectContext 中关系的变化的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法使用 NSPredicate 在核心数据中发出 NSDeleteRequest 与 NSFetchRequest ?

修改 NSFetchRequest 为空数组生成 NSRangeException 索引 0 超出范围

Swift Core Data NSFetchRequest 没有结果

核心数据 - NSFetchRequest 问题

MonoTouch 支持 NSFetchRequest 和 NSPredicate

NSFetchedResultsController 在 NSFetchRequest 中带有 NSDictionaryResultsType