【问题标题】:NSFetchedResultsController returning objects with null indexPathsNSFetchedResultsController 返回具有空 indexPaths 的对象
【发布时间】:2011-03-17 06:24:41
【问题描述】:

详细信息在 cmets 中。

以下代码:

// 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)'

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

更新: TechZen 想知道问题是否是由我的提醒实体引起的。我认为这是一个好主意,所以我做了以下事情:

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

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

以上代码在新的“无提醒实体”的基于窗口的应用程序中仍然失败。 (在这个新的测试应用程序中,实际上零代码是我自己编写的(在测试代码之外),它只是模板代码剪切和粘贴在一起。)

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

更新 请注意,正如 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]);

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

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 构建,那么它又可以正常工作了。所以我创建了一个new stackoverflow 帖子来问这个问题:如果你使用没有 UITableViewController 的 NSFetchedResultsController,你如何与对象交互? (因为 IndexPaths 不可靠)。

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

【问题讨论】:

  • 新的复制粘贴代码是否在同一个地方失败并出现同样的错误?
  • 是的,据我所知,但我在上面添加了新的输出以防万一。

标签: iphone cocoa cocoa-touch core-data nsfetchedresultscontroller


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      你需要做的

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

      不是吗?

      【讨论】:

        【解决方案4】:

        查看 fetchedResultsController 的 sortDescriptors 顺序。 Section key 字段必须先 sortDescriptor 才能按顺序。

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

        【讨论】:

          【解决方案5】:

          NSFetchedResultsController 的创建是什么样的?

          更新

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

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

          【讨论】:

          • 样板核心数据模板,仅更改了两个项目特定的部分:1. entityForName:@"Reminder" 2. initWithKey:@"textContent" 这是在粘贴箱中,以防有任何帮助那里:pastebin.com/TUhBKp7c
          • 嗨,马库斯,感谢您的跟进。重新线程,我不这么认为,但我不确定。我没有使用线程,所以我不知道要检查什么才能确定。但我对此表示怀疑,这个项目只是一个核心数据模板的略微修改版本。 (例如,我没有使用 NSThread)。我很好奇的一件事是 NSFetchedResultController 默认是否使用自己的线程? IE。如果你做了一个非常大的获取,它会冻结应用程序直到它完成吗?我很好奇,因为 uitableviews 的工作方式似乎可以异步填充。
          • (重新粘贴,是的,我知道我可以更新问题,但似乎添加了很多样板代码。我不知道这是否是正确的决定。)
          【解决方案6】:

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

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


          编辑:

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

          【讨论】:

          • 您好 TechZen,感谢您的回复。请注意,我说“如果我使用“基于导航的应用程序”,代码将按预期工作。”我通过将 Reminder 数据模型导入 Core Data 导航模板对此进行了测试。在这种情况下,代码可以正常工作。我想做的是让它与使用“基于窗口的应用程序”模板(仅限 iPad 的应用程序)创建的项目一起工作。尽管如此,通过删除 Reminder 实体来简化测试是一个好主意,所以我制作了一个测试应用程序来做到这一点。它仍然失败,详细信息在上面的更新中。再次感谢。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-13
          相关资源
          最近更新 更多