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

发布于 2024-08-27 22:22:21 字数 1516 浏览 9 评论 0原文

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

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

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

在合并期间,步骤 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.  
    }
}

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

我觉得这是我所缺少的一些简单的东西,并且可以在正确的方向上推动。

I have a table view that is managed by an NSFetchedResultsController. I am having an issue with a find-or-create operation, however. When the user hits the bottom of my table view, I am querying my server for another batch of content. If it doesn't exist in the local cache, we create it and store it. If it does exist, however, I want to append that data to the fetched results controller and display it. I can't quite figure that part out.

Here's what I'm doing thus far:

  1. The NSFetchedRequestController when initialized queries for the latest 100 results from the database (using setFetchLimit:). Even if there are 1000 rows, I only want 100 accessible at first.
  2. Passing the returned array of values from my server to an NSOperation to process.
  3. In the operation, create a new managed object context to work with.
  4. In the operation, I iterate through the array and execute a fetch request to see if the object exists (based on its server id).
  5. If the object doesn't exist, we create it and insert it into the operations' managed object context.
  6. After the iteration completes, we save the managed object context, which triggers a merge notification on my main thread.

During the merge, the newly created objects from step 4 are inserted into the table, but any object that already existed and was just fetched does not. Here's the relevant code from my 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.  
    }
}

What I want to pass to my main thread is the newly created objects plus any existing objects that may have been fetched in the fetch request each time the loop iterates.

I feel like it's something simple I'm missing, and could use a nudge in the right direction.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烟凡古楼 2024-09-03 22:22:21

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

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

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

更新

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

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

At this point, any objects that weren't locally cached in my Core Data store before will appear, but the ones that previously existed do not come along for the ride.

Can you explain this a little? I am not sure what you mean by the ones that previously existed. Is it objects that didn't match the filter on your table that now do after the retrieval or are you saying that the previous objects disappear from the table?

Also, how are you implementing the delegate methods for the NSFetchedResultsController? Are you doing a simple table reload or are you inserting/moving rows?

Update

There are a couple of ways to do this but they would require some experimentation on your part. I would first play with the idea of "touching" the objects that were fetched. Perhaps updating a 'lastAccessed' date or something so that these objects will come across the merge as "updated". I suspect that is the easiest path.

Baring that, another option would be to broadcast a notification of those objects back to the main thread (using their NSManagedObjectID as the carrier across the thread boundaries) so that you can manually update them; however that is less than ideal.

海的爱人是光 2024-09-03 22:22:21

嘿 Justin,您的 fetchLimit 会导致这种情况吗?

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

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

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

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

我还尝试了 fetchLimit 方法,这也有效。您不需要删除 &重建 NSFetchedResultsController ,您只需调整 fetchRequest 的 fetchLimit 即可:

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

Hey Justin, could your fetchLimit be causing this?

The NSFetchedRequestController when
initialized queries for the latest 100
results from the database (using
setFetchLimit:). Even if there are
1000 rows, I only want 100 accessible
at first.

You will still have a limit of 100 results on the NSFetchedResultsController no matter how many managed objects you insert & merge.

Do you have a sorting turned on? If so, some of the inserted managed objects might be showing up because they displace some of the existing 100 due to the ordering of results.

I've gone through the same issues with fetching "pages" of results, and went with a lower-bound constraint on my fetch (using the sorted attribute in an NSComparisonPredicate) and adjusting that with the last item in the most recent "page" of results.

I also tried the fetchLimit approach, and that worked too. You don't need to remove & rebuild the NSFetchedResultsController, you can just adjust the fetchLimit of the fetchRequest:

tableMaxItems += 100;
[myFRC.fetchRequest setFetchLimit:tableMaxItems];
孤独患者 2024-09-03 22:22:21

这就是我最终解决这个问题的方法。在合并 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];
}

Here is how I ended up fixing this. Prior to merging in the changes from my NSOperation's MOC, I iterate through the values stored in NSUpdatedObjectsKey and touch them with willAccessValueForKey. To get them into NSUpdatedObjects key I took Marcus' advice above and added a lastAccessed property that I set to the current date in the NSOperation if the object already existed in the persistent store..

- (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];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文