在查找或创建循环期间将数据附加到 NSFetchedResultsController

Posted

技术标签:

【中文标题】在查找或创建循环期间将数据附加到 NSFetchedResultsController【英文标题】:Appending data to NSFetchedResultsController during find or create loop 【发布时间】:2010-04-07 05:16:30 【问题描述】:

我有一个由 NSFetchedResultsController 管理的表视图。但是,我遇到了查找或创建操作的问题。当用户点击我的表格视图的底部时,我正在向我的服务器查询另一批内容。如果它在本地缓存中不存在,我们创建它并存储它。但是,如果它确实存在,我想将该数据附加到获取的结果控制器并显示它。我不太清楚那部分。

这是我目前正在做的事情:

    NSFetchedRequestController 初始化查询数据库中最新的 100 个结果时(使用setFetchLimit:)。即使有 1000 行,我也只希望一开始可以访问 100 行。 将返回的值数组从我的服务器传递到 NSOperation 进行处理。 在操作中,创建一个新的托管对象上下文来使用。 在操作中,我遍历数组并执行获取请求以查看对象是否存在(基于其服务器 ID)。 如果对象不存在,我们创建它并将其插入操作的托管对象上下文中。 迭代完成后,我们保存托管对象上下文,这会在我的主线程上触发合并通知。

在合并过程中,步骤 4 中新创建的对象被插入到表中,但任何已经存在且刚刚获取的对象都不会插入。这是我的 NSOperation 中的相关代码

for (NSDictionary *resultsDict in self.results)

    NSNumber *dbID = [NSNumber numberWithLong:[[resultsDict valueForKey:@"id"] longValue]];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[NSEntityDescription entityForName:kResultEntityName inManagedObjectContext:moc]];
    [fetchRequest setPredicate:[NSPredicate predicateWithFormat: @"(dbID == %@)", dbID]];

    NSError *error = nil;

    NSManagedObject *newObject = nil;
    // Query the data store to see if the object exists
    newObject = [[moc executeFetchRequest:fetchRequest error:&error] lastObject];
    [fetchRequest release];

    // If it doesn't exist, create it.
    if ((tweet == nil))
    
        // Create the NSManagedObject and insert it into the MOC.  
    

我想要传递给我的主线程的是新创建的对象以及每次循环迭代时可能在获取请求中获取的任何现有对象。

我觉得我缺少一些简单的东西,并且可以在正确的方向上使用轻推。

【问题讨论】:

【参考方案1】:

此时,之前未在我的 Core Data 存储中本地缓存的任何对象都会出现,但之前存在的对象不会出现。

你能解释一下吗?我不确定你所说的以前存在的那些是什么意思。是与您表上的过滤器不匹配的对象现在在检索后执行,还是您说之前的对象从表中消失了?

另外,您如何实现NSFetchedResultsController 的委托方法?您是在进行简单的表格重新加载还是在插入/移动行?

更新

有几种方法可以做到这一点,但它们需要您进行一些实验。我会首先尝试“触摸”获取的对象的想法。也许更新“lastAccessed”日期或其他内容,以便这些对象将合并作为“更新”。我怀疑这是最简单的路径。

除此之外,另一种选择是将这些对象的通知广播回主线程​​(使用它们的NSManagedObjectID 作为跨线程边界的载体),以便您可以手动更新它们;但这并不理想。

【讨论】:

我稍微澄清了这个问题并添加了一些代码。结果控制器委托只是实现controllerDidChangeContent: 以在结果合并到主 MOC 后重新加载表。【参考方案2】:

嗨,贾斯汀,你的 fetchLimit 会不会造成这种情况?

NSFetchedRequestController当 最近 100 个的初始化查询 来自数据库的结果(使用 setFetchLimit:)。即使有 1000 行,我只想要 100 行 一开始。

无论您插入和合并多少托管对象,NSFetchedResultsController 上的结果仍将限制为 100 个。

您是否打开了排序?如果是这样,一些插入的托管对象可能会显示出来,因为它们会因结果的排序而取代现有的 100 个对象。

我在获取结果的“页面”时遇到了同样的问题,并且对我的获取设置了下限约束(使用 NSComparisonPredicate 中的 sorted 属性)并使用最后一项进行调整最近的“页面”结果。

我也尝试了 fetchLimit 方法,它也很有效。您不需要删除和重建NSFetchedResultsController,您只需调整 fetchRequest 的 fetchLimit:

tableMaxItems += 100;
[myFRC.fetchRequest setFetchLimit:tableMaxItems];

【讨论】:

【参考方案3】:

这是我最终解决此问题的方法。在合并来自我的NSOperation 的 MOC 的更改之前,我遍历存储在NSUpdatedObjectsKey 中的值并使用 willAccessValueForKey 触摸它们。为了让它们进入NSUpdatedObjects 键,我接受了 Marcus 上面的建议,并添加了一个 lastAccessed 属性,如果该对象已经存在于持久存储中,我将其设置为NSOperation 中的当前日期..

- (void)mergeChanges:(NSNotification *)notification

  NSAssert([NSThread mainThread], @"Not on the main thread");  
  NSSet *updatedObjects = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];

  for (NSManagedObject *object in updatedObjects)
  
    [[managedObjectContext objectWithID:[object objectID]] willAccessValueForKey:nil];
  

  [managedObjectContext mergeChangesFromContextDidSaveNotification:notification];

【讨论】:

如果答案是正确的,习惯上将其标记为答案:)

以上是关于在查找或创建循环期间将数据附加到 NSFetchedResultsController的主要内容,如果未能解决你的问题,请参考以下文章

Python-在while循环期间将列表附加到列表-结果与预期不符[重复]

从for循环将系列附加到dict或list或dataframe?

将事件处理程序附加到在循环内创建的表单

为每个循环附加到一个新列表

如何在 laravel 身份验证期间附加到用户创建多个复选框

jQuery 循环创建 div 并将内容附加到它们