NSFetchedResultsController 返回索引路径为空的对象

发布于 2024-09-10 22:04:40 字数 6210 浏览 6 评论 0原文

详情见评论。

以下代码:

// Perform the fetch...
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

// Confirm that objects were fetched by counting them...
NSLog(@"Number of Objects = %i",
      [[fetchedResultsController fetchedObjects] count]);

// Confirm that sections exist by counting them...
NSLog(@"Numbers of Sections = %i",
      [[fetchedResultsController sections] count]); 

for (id section in [fetchedResultsController sections]) {
    // Count number of objects in each section
    // _The fact that this outputs 0 is the first sign of trouble_
    NSLog(@"Number of Objects in Section = %i", [section numberOfObjects]);
}

for (Reminder *reminder in [fetchedResultsController fetchedObjects]) {
    // Confirm that the objects fetched are in fact real objects
    // by accessing their "textContent" property...
    NSLog(@"textContent=%@", reminder.textContent);

    // Show that the fetched objects are being returned 
    // with a (null) indexPath...
    // _The second sign of trouble..._
    NSLog(@"IndexPath=%@",
          [fetchedResultsController indexPathForObject:reminder]);
}

NSUInteger indexArr[] = {0,0};
NSIndexPath *indexPath = [NSIndexPath indexPathWithIndexes:indexArr 
                                                    length:2];

// _Application crashes on this line because the fetched 
// objects do not have indexPaths_
Reminder *testReminder = (Reminder *)[fetchedResultsController 
                                      objectAtIndexPath:indexPath]; 
NSLog(@"textContent = %@", testReminder.textContent);

产生以下输出:

2010-07-17 00:48:41.865 Reminders[27335:207] Number of Objects = 3
2010-07-17 00:48:41.867 Reminders[27335:207] Numbers of Sections = 1
2010-07-17 00:48:41.868 Reminders[27335:207] Number of Objects in Section = 0
2010-07-17 00:48:41.870 Reminders[27335:207] textContent=Imported Object 3
2010-07-17 00:48:41.871 Reminders[27335:207] IndexPath=(null)
2010-07-17 00:48:41.873 Reminders[27335:207] textContent=Imported Object 2
2010-07-17 00:48:41.873 Reminders[27335:207] IndexPath=(null)
2010-07-17 00:48:41.874 Reminders[27335:207] textContent=Imported Object 1
2010-07-17 00:48:41.875 Reminders[27335:207] IndexPath=(null)
2010-07-17 00:48:41.887 Reminders[27335:207] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'

任何想法将不胜感激。仅供参考,如果我使用不同的模板作为起点,上面的代码可以在单独的应用程序中完美运行。即,如果我使用“基于窗口的应用程序”模板,代码将失败。如果我使用“基于导航的应用程序”,代码将按预期工作。

更新:TechZen 想知道问题是否是由我的提醒实体引起的。我认为这是一个值得研究的好主意,因此我执行了以下操作:

  1. 创建两个默认模板应用程序:一个“基于窗口的应用程序”和一个“基于导航的应用程序”(均启用了核心数据)

  2. 将基于导航的应用程序复制到基于窗口的应用程序所需的最少代码执行上述测试(几乎只是“xcdatamodel”文件、fetchedresultscontroller 和添加测试对象的方法)。

上面的代码在新的“Reminder-entity free”基于窗口的应用程序中仍然失败。 (在这个新的测试应用程序中,实际上我自己编写的代码为零(在测试代码之外),这一切都只是剪切并粘贴在一起的模板代码。)

所以现在,我正在寻找任何方式 在创建“基于窗口的应用程序”后运行上述代码。以下是使用基于导航的默认实体执行测试的代码,以防有人有兴趣尝试一下:

更新 请注意,正如 TechZen 下面所指出的,无论运行什么,此代码都会崩溃使用空数据库,因此如果从基于窗口的应用程序开始,请首先向数据库添加一些对象,然后添加测试代码。

// Confirm that objects were fetched
NSLog(@"Number of Objects = %i",
      [[fetchedResultsController fetchedObjects] count]);

// Confirm that sections exist
NSLog(@"Numbers of Sections = %i",
      [[fetchedResultsController sections] count]); 

for (id section in [fetchedResultsController sections]) {

    // Count number of objects in sections
    // _The fact that this outputs 0 is the first sign of trouble_
    NSLog(@"Number of Objects in Section = %i", [section numberOfObjects]);
}

for (NSManagedObject *managedObject in [fetchedResultsController fetchedObjects]) {

    // Confirm that the objects fetched are in fact real objects, 
    // by accessing their "timeStamp" property
    NSLog(@"TimeStamp=%@", [[managedObject valueForKey:@"timeStamp"] description]);

    // Show that the fetched objects are being returned 
    // with a (null) indexPath
    // _The second sign of trouble..._
    NSLog(@"IndexPath=%@",
          [fetchedResultsController indexPathForObject:managedObject]);
}

NSUInteger indexArr[] = {0,0};
NSIndexPath *indexPath = [NSIndexPath indexPathWithIndexes:indexArr 
                                                    length:2];

// _Application crashes on this line, because the fetched 
// objects do not have indexPaths_
NSManagedObject *managedObject = [fetchedResultsController 
                                  objectAtIndexPath:indexPath];
NSLog(@"textContent = %@", [[managedObject valueForKey:@"timeStamp"] description]);

更新这是使用新的剪切粘贴代码时的输出

2010-07-18 15:33:41.264 Reminders[30898:207] Number of Objects = 3
2010-07-18 15:33:41.266 Reminders[30898:207] Numbers of Sections = 1
2010-07-18 15:33:41.267 Reminders[30898:207] Number of Objects in Section = 0
2010-07-18 15:33:41.270 Reminders[30898:207] TimeStamp=2010-07-18 13:59:00 -0400
2010-07-18 15:33:41.271 Reminders[30898:207] IndexPath=(null)
2010-07-18 15:33:41.272 Reminders[30898:207] TimeStamp=2010-07-18 13:59:00 -0400
2010-07-18 15:33:41.273 Reminders[30898:207] IndexPath=(null)
2010-07-18 15:33:41.274 Reminders[30898:207] TimeStamp=2010-07-18 13:58:59 -0400
2010-07-18 15:33:41.275 Reminders[30898:207] IndexPath=(null)
2010-07-18 15:33:41.276 Reminders[30898:207] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'

更新所以我将这个问题缩小到与SDK版本相关的问题,我现在有一个项目如果我使用 Simulator 3.2 构建它会崩溃,而使用 Simulator 3.1.3 构建它工作正常。但是如果我添加 UITableViewController,然后使用 Simulator 3.2 进行构建,那么它会再次正常工作。因此,我创建了一个 新的 stackoverflow 帖子来提出问题:如果您使用 NSFetchedResultsController 而不使用 UITableViewController,如何与对象交互? (因为 IndexPaths 不可靠)。

更新 此问题(暂时)通过使用 -[NSFetchedResultsController fetchedObjects] objectAtIndex:] 访问对象来解决。

Details are in the comments.

The following code:

// Perform the fetch...
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

// Confirm that objects were fetched by counting them...
NSLog(@"Number of Objects = %i",
      [[fetchedResultsController fetchedObjects] count]);

// Confirm that sections exist by counting them...
NSLog(@"Numbers of Sections = %i",
      [[fetchedResultsController sections] count]); 

for (id section in [fetchedResultsController sections]) {
    // Count number of objects in each section
    // _The fact that this outputs 0 is the first sign of trouble_
    NSLog(@"Number of Objects in Section = %i", [section numberOfObjects]);
}

for (Reminder *reminder in [fetchedResultsController fetchedObjects]) {
    // Confirm that the objects fetched are in fact real objects
    // by accessing their "textContent" property...
    NSLog(@"textContent=%@", reminder.textContent);

    // Show that the fetched objects are being returned 
    // with a (null) indexPath...
    // _The second sign of trouble..._
    NSLog(@"IndexPath=%@",
          [fetchedResultsController indexPathForObject:reminder]);
}

NSUInteger indexArr[] = {0,0};
NSIndexPath *indexPath = [NSIndexPath indexPathWithIndexes:indexArr 
                                                    length:2];

// _Application crashes on this line because the fetched 
// objects do not have indexPaths_
Reminder *testReminder = (Reminder *)[fetchedResultsController 
                                      objectAtIndexPath:indexPath]; 
NSLog(@"textContent = %@", testReminder.textContent);

Results in the following output:

2010-07-17 00:48:41.865 Reminders[27335:207] Number of Objects = 3
2010-07-17 00:48:41.867 Reminders[27335:207] Numbers of Sections = 1
2010-07-17 00:48:41.868 Reminders[27335:207] Number of Objects in Section = 0
2010-07-17 00:48:41.870 Reminders[27335:207] textContent=Imported Object 3
2010-07-17 00:48:41.871 Reminders[27335:207] IndexPath=(null)
2010-07-17 00:48:41.873 Reminders[27335:207] textContent=Imported Object 2
2010-07-17 00:48:41.873 Reminders[27335:207] IndexPath=(null)
2010-07-17 00:48:41.874 Reminders[27335:207] textContent=Imported Object 1
2010-07-17 00:48:41.875 Reminders[27335:207] IndexPath=(null)
2010-07-17 00:48:41.887 Reminders[27335:207] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'

Any ideas would be greatly appreciated. FYI, the above code works perfectly in a separate application if I use a different template as a starting point. I.e. if I use the "Window-based application" template, the code will fail. If I use "Navigation-based application" the code works as expected.

Update: TechZen was wondering if the problem is caused by my Reminder entity. I thought this was a good idea to look into, so I did the following:

  1. Create two default template applications: a "Window-based application" and a "Navigation-based Application" (both with Core Data enabled)

  2. Copied over the minimum code needed from the Nav-based to the Window-based to perform the above test (pretty much just the "xcdatamodel" file, the fetchedresultscontroller, and a way to add test objects).

The above code still fails in the new "Reminder-entity free" window-based application. (In this new test application there is in fact zero code I've authored myself (outside of the test code), it's all just template code cut-and-pasted together.)

So now, I am looking for any way to get the above code to run after creating a "Window-based application". Here is the code to perform the test using the nav-based's default entity, in case anyone is interested in giving it a try:

UPDATE Note that as TechZen noted below this code will crash no matter what if run with an empty database, so if starting from a window-based application, first add a few objects to the database then add the test code.

// Confirm that objects were fetched
NSLog(@"Number of Objects = %i",
      [[fetchedResultsController fetchedObjects] count]);

// Confirm that sections exist
NSLog(@"Numbers of Sections = %i",
      [[fetchedResultsController sections] count]); 

for (id section in [fetchedResultsController sections]) {

    // Count number of objects in sections
    // _The fact that this outputs 0 is the first sign of trouble_
    NSLog(@"Number of Objects in Section = %i", [section numberOfObjects]);
}

for (NSManagedObject *managedObject in [fetchedResultsController fetchedObjects]) {

    // Confirm that the objects fetched are in fact real objects, 
    // by accessing their "timeStamp" property
    NSLog(@"TimeStamp=%@", [[managedObject valueForKey:@"timeStamp"] description]);

    // Show that the fetched objects are being returned 
    // with a (null) indexPath
    // _The second sign of trouble..._
    NSLog(@"IndexPath=%@",
          [fetchedResultsController indexPathForObject:managedObject]);
}

NSUInteger indexArr[] = {0,0};
NSIndexPath *indexPath = [NSIndexPath indexPathWithIndexes:indexArr 
                                                    length:2];

// _Application crashes on this line, because the fetched 
// objects do not have indexPaths_
NSManagedObject *managedObject = [fetchedResultsController 
                                  objectAtIndexPath:indexPath];
NSLog(@"textContent = %@", [[managedObject valueForKey:@"timeStamp"] description]);

UPDATE here is the output when using the new cut-and-pasted code

2010-07-18 15:33:41.264 Reminders[30898:207] Number of Objects = 3
2010-07-18 15:33:41.266 Reminders[30898:207] Numbers of Sections = 1
2010-07-18 15:33:41.267 Reminders[30898:207] Number of Objects in Section = 0
2010-07-18 15:33:41.270 Reminders[30898:207] TimeStamp=2010-07-18 13:59:00 -0400
2010-07-18 15:33:41.271 Reminders[30898:207] IndexPath=(null)
2010-07-18 15:33:41.272 Reminders[30898:207] TimeStamp=2010-07-18 13:59:00 -0400
2010-07-18 15:33:41.273 Reminders[30898:207] IndexPath=(null)
2010-07-18 15:33:41.274 Reminders[30898:207] TimeStamp=2010-07-18 13:58:59 -0400
2010-07-18 15:33:41.275 Reminders[30898:207] IndexPath=(null)
2010-07-18 15:33:41.276 Reminders[30898:207] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)'

UPDATE So I narrowed this problem down to being an SDK version-related issue, I now have a project that if I build with Simulator 3.2 it crashes, and build with Simulator 3.1.3 it works fine. BUT if I add a UITableViewController, then build with Simulator 3.2, then it works fine again. So I've created a new stackoverflow post to ask the question: If you are using NSFetchedResultsController without a UITableViewController, how do you interact with the objects? (since the IndexPaths are unreliable).

UPDATE This issue is (tentatively) solved by using -[NSFetchedResultsController fetchedObjects] objectAtIndex:] to access the objects.

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

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

发布评论

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

评论(6

素年丶 2024-09-17 22:04:40

您是否尝试过在仅内存跟踪模式下使用NSFetchedResultsController? (仅内存跟踪:委托非nil并且文件缓存名称设置为nil)

Have you tried to use NSFetchedResultsController in Memory-Only-tracking mode? (Memory-only tracking: the delegate is non-nil and the file cache name is set to nil)

遮了一弯 2024-09-17 22:04:40

这可以通过使用 -[NSFetchedResultsController fetchedObjects] objectAtIndex:] 绕过

This can be bypassed by using -[NSFetchedResultsController fetchedObjects] objectAtIndex:]

拧巴小姐 2024-09-17 22:04:40

我想我会很愚蠢地指出这一点
NSLog(@"%@",indexPath) 总是返回 null?

你需要做

NSLog(@"section %i",(int)indexPath.section);
NSLog(@"row %i",(int)indexPath.row);

不是吗?

I suppose I'd be silly to point out that
NSLog(@"%@",indexPath) will always return null?

You need to do

NSLog(@"section %i",(int)indexPath.section);
NSLog(@"row %i",(int)indexPath.row);

Don't you?

姐不稀罕 2024-09-17 22:04:40

查看fetchedResultsController的sortDescriptors顺序。部分关键字段必须首先按顺序排序描述符。

如果 fetchedResultsController 有多个 sortDescriptor 并且第一个描述符不是节键字段,则 indexPathForObject: 方法无法解析 indexPath。

Look at the sortDescriptors order of fetchedResultsController. Section key field must first sortDescriptor in order.

If fetchedResultsController have more than one sortDescriptor and first descriptor isn't section key field than indexPathForObject: method couldn't resolve indexPath.

枫以 2024-09-17 22:04:40

NSFetchedResultsController 的创建过程是什么样的?

更新

仅供参考,您可以使用代码更新您的问题,而不是使用 PasteBin。

您是否在此代码中的任何位置使用多个线程来访问 NSFetchedResultsController ?

What does the creation of the NSFetchedResultsController look like?

Update

FYI, you can update your question with the code instead of using PasteBin.

Are you using multiple threads in this code anywhere to access the NSFetchedResultsController?

东北女汉子 2024-09-17 22:04:40

我将您的代码复制并粘贴到默认的 Core Data 导航模板中,将实体更改为带有 textContent 字符串属性的 Reminder,并且运行良好。这段代码或获取结果控制器的设置没有任何问题。

我认为问题实际上出在您的 Reminder 实体、Reminder 类或 textContent 属性或对象上。这些错误可能是由于无法正确处理提醒对象而引起的。


编辑:

确保仅在将某些对象添加到上下文后才运行此测试。如果没有对象,它就会崩溃。我将使用基于窗口的模板进行测试。

I copied and pasted your code into the default Core Data navigation template, altered the entity to Reminder with a string attribute of textContent and it ran fine. There is nothing wrong with this code or the setup of the fetched results controller.

I think that the problem is actually with either your Reminder entity, the Reminder class or the textContent attribute or object. These errors could be caused by not being able to properly process the Reminder objects.


Edit:

Make sure you only run this test after some objects have been added to the context. It will crash if there are no objects. I'll test with a window-based template.

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