Objective c NSFetchedResultsController不';即使在数据库中创建了项,也无法获取结果

Objective c NSFetchedResultsController不';即使在数据库中创建了项,也无法获取结果,objective-c,core-data,ios5,Objective C,Core Data,Ios5,我是iOS新手,所以如果这很简单,我道歉。。。在开始实现我的完整应用程序之前,我一直在反复研究一些小的概念验证应用程序,这样它就不会像以前那样让人难以承受了。当我按照苹果网站上的“你的第二个iOS应用程序”教程创建表视图时,我的表视图工作正常。现在我已经尝试在选项卡栏应用程序中创建它,但我发现NSFetchedResultsController存在问题,我不确定它是否与我在情节提要中出错的内容有关,或者与其他内容有关 我有一个选项卡栏控制器,它连接到嵌入在导航控制器中的表视图控制器(Catalo

我是iOS新手,所以如果这很简单,我道歉。。。在开始实现我的完整应用程序之前,我一直在反复研究一些小的概念验证应用程序,这样它就不会像以前那样让人难以承受了。当我按照苹果网站上的“你的第二个iOS应用程序”教程创建表视图时,我的表视图工作正常。现在我已经尝试在选项卡栏应用程序中创建它,但我发现NSFetchedResultsController存在问题,我不确定它是否与我在情节提要中出错的内容有关,或者与其他内容有关

我有一个选项卡栏控制器,它连接到嵌入在导航控制器中的表视图控制器(CatalogViewController.h/m)。表视图控制器配置为具有静态单元格。在第一个静态单元格中,我有一个到另一个表视图控制器(FoodCatalogViewController.h/m)的推送序列,该控制器配置为使用动态原型-这是我希望从数据库(从食物实体-当前仅显示名称和卡路里)中看到对象的视图。此视图有一个“添加”按钮,用于在数据库中创建新条目-添加按钮有一个到另一个静态表视图(AddFoodViewController.h/m)的模式序列,该静态表视图嵌入到它自己的导航控制器中。我知道“添加”按钮正在工作,并且它的视图正确连接到数据库(即,我正在正确传递/设置NSManagedObjectContext),因为如果我使用“sqlite数据库浏览器”打开应用程序的sqlite数据库文件,我会看到我在模拟器中添加的项目。我只是不明白为什么它们没有通过NSFetchedResultsController显示在我的表视图中。我使用断点逐步检查了代码,并确认正在我的FoodCatalogViewController的fetchedResultsController函数中调用performFetch代码。我在numberOfRowsInSection代码中添加了一个调试NSLog行,它似乎为零,因此我从未进入cellForRowAtIndexPath或configureCell。所以看起来NSFetchedResultsController是罪魁祸首-我只是不知道为什么它不能正确获取结果,以及我可以做些什么来进一步调试它。有人能帮我吗

为了通过层次结构传递核心数据信息,我有以下代码段:

AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;

    // Setup the Catalogs Tab
    UINavigationController *navigationController = [[tabBarController viewControllers] objectAtIndex:0];
    CatalogViewController *catalogViewController = [[navigationController viewControllers] objectAtIndex:0];
    catalogViewController.managedObjectContext = self.managedObjectContext;
    return YES;
}
CatalogViewController.m(序列中的第一个表视图控制器-我将NSManagedObjectContext传递给它):

FoodCatalogViewController.h(序列中的第二个表视图控制器-我使用NSManagedObjectContext设置NSFetchedResultsController):

FoodCatalogViewController.m(要添加到数据库的AddFoodViewController协议代码):

更多调试信息
奇怪-看起来fetchedResultsController在FoodCatalogViewController中无法正常工作,即使managedObjectContext似乎正在工作。。。下面是来自FoodCatalogViewController.m的修改过的fetchedResultsController函数,其中包含一些调试NSLog语句,并将self.fetchedResultsController替换为u fetchedResultsController(因为我想知道这是否是导致问题的原因)

以下是fetchedResultsController函数NSLog调用的输出:

2012-01-29 10:22:21.118 UltraTrack[19294:fb03] Result: (
    "<Food: 0x6e651b0> (entity: Food; id: 0x6e64630 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p1> ; data: <fault>)",
    "<Food: 0x6e653e0> (entity: Food; id: 0x6e61870 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p3> ; data: <fault>)",
    "<Food: 0x6e65450> (entity: Food; id: 0x6e64420 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p4> ; data: <fault>)",
    "<Food: 0x6e654c0> (entity: Food; id: 0x6e64430 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p5> ; data: <fault>)",
    "<Food: 0x6e65530> (entity: Food; id: 0x6e64e80 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p2> ; data: <fault>)",
    "<Food: 0x6e655b0> (entity: Food; id: 0x6e64e90 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p6> ; data: <fault>)"
)
2012-01-29 10:22:21.907 UltraTrack[19294:fb03] Number or objects: 6
有人认为部分是问题所在,因此我将numberOfSectionsInTableView硬编码为返回1,然后fetchResults中的第一个对象似乎得到了正确处理,但我得到了以下异常:

2012-01-29 10:29:27.296 UltraTrack[19370:fb03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 1 in section at index 0'
如果我将numberOfRowsInSection硬编码为也返回1,则数据库中的第一个对象将正确显示在表视图中。fetchedResultsController中的节信息可能有什么问题?我是否可以在序列图像板中为表视图设置一些与节有关的错误内容

下面是我尝试过硬编码的两个表视图函数:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
    //NSLog(@"Number of sections in table view is %d", [[self.fetchedResultsController sections] count]);
    //return [[self.fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSLog(@"Number or objects: %d", [self.fetchedResultsController.fetchedObjects count]);
    // If I return 1, the object is displayed correctly, if I return count, I get the exception
    //return 1;
    return [self.fetchedResultsController.fetchedObjects count];

    // Return the number of rows in the section.
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    NSLog(@"Number of rows being returned is %d", [sectionInfo numberOfObjects]);
    return [sectionInfo numberOfObjects];
}
-(NSInteger)节数表视图:(UITableView*)表视图
{
返回1;
//NSLog(@“表视图中的节数为%d”,[[self.fetchedResultsController节数]);
//返回[[self.fetchedResultsController节]计数];
}
-(NSInteger)表视图:(UITableView*)表视图行数节:(NSInteger)节
{
NSLog(@“数量或对象:%d”,[self.fetchedResultsController.fetchedObject计数];
//如果我返回1,则对象显示正确;如果我返回count,则得到异常
//返回1;
返回[self.fetchedResultsController.fetchedObject计数];
//返回节中的行数。
id sectionInfo=[[self.fetchedResultsController节]objectAtIndex:section];
NSLog(@“返回的行数为%d”,[sectionInfo numberOfObjects]);
返回[sectionInfo numberOfObjects];
}

从您的描述来看,带章节的代码似乎是罪魁祸首。但实际上您并没有使用任何部分。因此,请尝试以下方法来简化:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.fetchedResultsController.fetchedObjects count];
}

如果仍然返回零行,请检查
fetchedResultsController
getter方法中的
fetchedObject.count

如果在保存数据的情况下重新启动应用程序,是否会显示在表视图中?这只是一个令人耳目一新的问题吗?不-当我重新启动应用程序时,它也不会显示。它总是空的,表视图中没有显示任何值。能否包括SQL输出,以及创建新对象的“添加视图”控制器中的代码?@jrturton,我刚刚添加了其他代码。您希望看到什么SQL输出?您最近的错误是因为您使用%@作为整数的格式说明符-使用%d。我想你可能没问题——我唯一发现的就是自我。在您的访问器中,您似乎已经解决了这个问题。我尝试了这个,看起来它在该部分中必须返回非零行数,但现在在我的configureCell函数中
#import <UIKit/UIKit.h>
@protocol AddFoodViewControllerDelegate;

@interface AddFoodViewController : UITableViewController <UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITextField *foodNameInput;
@property (weak, nonatomic) IBOutlet UITextField *caloriesInput;
@property (weak, nonatomic) id <AddFoodViewControllerDelegate> delegate;

- (IBAction)save:(id)sender;
- (IBAction)cancel:(id)sender;

@end

@protocol AddFoodViewControllerDelegate <NSObject>
- (void)addFoodViewControllerDidCancel:(AddFoodViewController *)controller;
- (void)addFoodViewControllerDidSave:(AddFoodViewController *)controller name:(NSString *)name calories:(NSNumber *)calories;
@end
#import "AddFoodViewController.h"

@implementation AddFoodViewController
@synthesize foodNameInput;
@synthesize caloriesInput;
@synthesize delegate = _delegate;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

- (void)viewDidUnload
{
    [self setFoodNameInput:nil];
    [self setCaloriesInput:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    if ((textField == self.foodNameInput) || (textField == self.caloriesInput )) {
        [textField resignFirstResponder];
    }
    return YES;
}

- (IBAction)save:(id)sender {
    int caloriesInt = [self.caloriesInput.text intValue];
    NSNumber *caloriesNum = [NSNumber numberWithInt:caloriesInt];
    [[self delegate] addFoodViewControllerDidSave:self name:self.foodNameInput.text calories:caloriesNum];
}

- (IBAction)cancel:(id)sender {
    [[self delegate] addFoodViewControllerDidCancel:self];
}
@end
- (void)addFoodViewControllerDidCancel:(AddFoodViewController *)controller {
    [self dismissViewControllerAnimated:YES completion:NULL];
}

- (void)addFoodViewControllerDidSave:(AddFoodViewController *)controller name:(NSString *)name calories:(NSNumber *)calories {
    if ([name length]) {
        [self addFoodWithName:name calories:calories];
        [[self tableView] reloadData];
    }
    [self dismissModalViewControllerAnimated:YES];
}

- (void) addFoodWithName:(NSString *)name calories:(NSNumber *)calories {
    // Create a new instance of the entity managed by the fetched results controller.
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
    NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
    NSLog(@"entity name is %@", [entity name]);
    NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

    // If appropriate, configure the new managed object.
    // Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
    [newManagedObject setValue:name forKey:@"name"];
    [newManagedObject setValue:calories forKey:@"calories"];
    CFUUIDRef uuidRef = CFUUIDCreate(NULL);
    CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);
    NSString* uuid = [NSString stringWithString:(__bridge NSString *)uuidStringRef];
    [newManagedObject setValue:uuid forKey:@"uuid"];

    // Save the context.
    NSError *error = nil;
    if (![context save:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }   
}
2012-01-29 10:22:21.118 UltraTrack[19294:fb03] Result: (
    "<Food: 0x6e651b0> (entity: Food; id: 0x6e64630 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p1> ; data: <fault>)",
    "<Food: 0x6e653e0> (entity: Food; id: 0x6e61870 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p3> ; data: <fault>)",
    "<Food: 0x6e65450> (entity: Food; id: 0x6e64420 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p4> ; data: <fault>)",
    "<Food: 0x6e654c0> (entity: Food; id: 0x6e64430 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p5> ; data: <fault>)",
    "<Food: 0x6e65530> (entity: Food; id: 0x6e64e80 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p2> ; data: <fault>)",
    "<Food: 0x6e655b0> (entity: Food; id: 0x6e64e90 <x-coredata://8A10B827-9F10-4760-934C-0061A982B73C/Food/p6> ; data: <fault>)"
)
2012-01-29 10:22:21.907 UltraTrack[19294:fb03] Number or objects: 6
- (NSFetchedResultsController *)fetchedResultsController
{
    if (__fetchedResultsController != nil) {
        return __fetchedResultsController;
    }

    // Set up the fetched results controller.
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Food" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
    NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Master"];
    aFetchedResultsController.delegate = self;
    __fetchedResultsController = aFetchedResultsController;

    NSArray *result = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
    NSLog(@"Result: %@", result);

    NSError *error = nil;
    if (![__fetchedResultsController performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    NSLog(@"Number or objects: %d", [__fetchedResultsController.fetchedObjects count]);

    return __fetchedResultsController;
}
2012-01-29 10:29:27.296 UltraTrack[19370:fb03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no object at index 1 in section at index 0'
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
    //NSLog(@"Number of sections in table view is %d", [[self.fetchedResultsController sections] count]);
    //return [[self.fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSLog(@"Number or objects: %d", [self.fetchedResultsController.fetchedObjects count]);
    // If I return 1, the object is displayed correctly, if I return count, I get the exception
    //return 1;
    return [self.fetchedResultsController.fetchedObjects count];

    // Return the number of rows in the section.
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    NSLog(@"Number of rows being returned is %d", [sectionInfo numberOfObjects]);
    return [sectionInfo numberOfObjects];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.fetchedResultsController.fetchedObjects count];
}