更新/插入 NSFetchedResultsController 中的现有对象

发布于 2024-10-05 02:15:55 字数 1856 浏览 1 评论 0原文

我将 NSFetchedResultsControllerUITableView 一起使用,它显示文件夹列表以及该文件夹中每个项目的关联未读计数。我想根据同步/刷新期间的未读计数(在利用 NSManagedObjectContextDidSaveNotification 的后台线程上)从 tableView 插入/删除带有动画的文件夹。没有未读项目的文件夹应该淡出,并且包含新的未读项目的现有文件夹应该淡入。

当前使用 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: 方法不会执行此操作,除非 tableView 完全打开重新加载,或者重新启动应用程序,这并不理想。

NSFetchedResultsController 不是执行此操作的方法吗?我最初的想法是创建一个单独的核心数据实体,仅保存包含未读项目的文件夹,并从中添加/删除文件夹,但这似乎很做作。

我的 NSPredicate 看起来像:

ANY items.unread == 1

更新: 上面的 NSPredicate 工作正常并抓取我期望的对象。我的问题是,如果应用程序启动并且FolderX有0个未读项目,则它不会出现。如果我随后刷新(退出并在后台线程中解析 JSON 文件)并且FolderX 现在有 25 个未读项目,它将不会自动淡入或触发 NSFetchedResultsChangeInsert 并且因为它一开始就没有包含在内,它也不会触发 NSFetchedResultsChangeUpdate 这就是为什么我认为解决方案是创建一个单独的实体,仅保存包含未读项目的文件夹并从中添加/删除同步期间。

我只是觉得我错过了一些非常明显的痛苦的事情。

更新2: 我通过消除我自己的应用程序的影响来尽可能简化问题,我可以在 Xcode 中的默认 Core Data 模板中复制它。

新问题: 有一个名为“Event”的实体,没有任何关系,并且有两个属性“Date”和“unreadCount”。我用 NSPredicate 设置了 NSFetchedResultsController,如下所示:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"unreadCount < 10"];

每次添加新对象时,都会以 unreadCount 为 15 创建该对象,然后所有现有对象都会减 1。这是在单独的 ManagedObjectContext 上完成的(以复制后台处理) ,但都是在主线程上完成的)。

我已经实现了controllerWillChangeContent和相关方法,我期望发生的是,在现有对象(unreadCount为15)递减5次(现在为10)之后,它应该被插入到tableView中,因为它现在与谓词。这根本不是发生的情况,除非重新启动应用程序,否则该对象根本不会出现。

我附加了一个示例项目,只需运行它并单击“添加”按钮几次(什么也不会发生)。重新启动应用程序,您将在 tableView 中看到一些对象,如果您再单击“添加”按钮几次,这些对象将自行删除,但不会添加新对象。

如果 NSFetchedResultsController 不是让这种行为发挥作用的解决方案,那么什么是呢?

示例项目: http://dl.dropbox.com/u/521075/BGUpdating.zip< /a>

I'm using NSFetchedResultsController with a UITableView which displays a list of folders and associated unread counts for each item in that folder. I'd like to insert/delete folders w/ animation from the tableView based on the unread count during a sync/refresh (on a background thread utilizing NSManagedObjectContextDidSaveNotification). Folders with no unread items should fade out, and existing folders with new unread items should fade in.

Currently using the controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: method does not do this unless the tableView is completely reloaded, or the app is relaunched, which is not ideal.

Is NSFetchedResultsController not the way to do this? My initial idea was to create a separate Core Data entity that only holds the folders with unread items, and add/remove folders from that, but that just seems hokey.

My NSPredicate looks something like:

ANY items.unread == 1

Update:
The above NSPredicate works fine and grabs the objects that I expect it to. My problem is that if the app launches and FolderX has 0 unread items, it does not appear. If I then refresh (goes out and parses a JSON file in a background thread) and FolderX now has 25 unread items, it will not automatically fade in or trigger NSFetchedResultsChangeInsert and since it wasn't included in the first place, it also doesn't trigger NSFetchedResultsChangeUpdate which is why I thought the solution was to create a separate Entity that only holds Folders with unread items and add/remove from that during sync.

I just feel like I'm missing something painfully obvious.

Update 2:
I've simplified the problem as much as I can by removing the influence of my own app, I'm able to replicate it in the default Core Data template in Xcode.

The New Problem:
There is a single Entity named "Event" with no relationships and two properties, "Date" and "unreadCount". I have NSFetchedResultsController set up with an NSPredicate that looks like:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"unreadCount < 10"];

Every time a new object is added, it is created with an unreadCount of 15, then all existing objects are decremented by 1. This is done on a separate ManagedObjectContext (to replicate background processing, but is all done on the main thread).

I've implemented the controllerWillChangeContent and related methods, and what I expected to happen was that after an existing object (with unreadCount of 15) is decremented 5 times (to now be 10) it should be inserted into the tableView because it now matches the predicate. This is not at all what happens, the object does not appear at all unless the app is restarted.

I've attached a sample project, simply run it and click the Add button a few times (nothing will happen). Restart the app and you will see a handful of objects now in the tableView, if you click the Add button a few more times those objects will remove themselves, but new objects will not get added.

If NSFetchedResultsController is not the solution to get this behavior to work, then what is?

Sample Project: http://dl.dropbox.com/u/521075/BGUpdating.zip

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

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

发布评论

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

评论(1

迷雾森÷林ヴ 2024-10-12 02:15:55

您的谓词无法跨越两个或多个对多关系。您目前拥有:

type == folder AND ANY (set of folders).(set of items).unread == 1

您不能使用 ANY 来横贯任意数量的关系。相反,您可能需要一个子查询,例如:

type == folder AND (0!=SUBQUERY(folder,$f,0!=SUBQUERY($f.items,$i,$i.unread==1).@count).@count)

我认为您可能在错误的实体上执行提取。如果您要呈现 Folder 对象表,则应该对 Folder 实体执行提取。仅此一点就可以简化一切。那么你的谓词就是:

ANY items.unread==1

Your predicate will not work crossing two or more to-many relationships. You have at present:

type == folder AND ANY (set of folders).(set of items).unread == 1

You can't use ANY to transverse an arbitrary number of relationships. Instead, you probably need a subquery like:

type == folder AND (0!=SUBQUERY(folder,$f,0!=SUBQUERY($f.items,$i,$i.unread==1).@count).@count)

I think you maybe performing the fetch on the wrong entity. If you are presenting a table of Folder objects, you should be performing the fetch on the Folder entity. That alone would simplify everything. Your predicate would then be just:

ANY items.unread==1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文