NSFetchedResultsController没有按预期获取

时间:2014-01-10 21:01:09

标签: ios objective-c core-data nsfetchedresultscontroller

我在iOS应用中使用了以下NSFetchedResultsController:

- (NSFetchedResultsController *)fetchedResultsController {

    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"ToDoItems" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    NSSortDescriptor *sort = [[NSSortDescriptor alloc]
                              initWithKey:@"tdText" ascending:NO];
    [fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];

    [fetchRequest setFetchBatchSize:20];

    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
                                                   cacheName:@"Root"];
    self.fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;

}

要测试它我使用以下代码:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    int numero = [self.fetchedResultsController.fetchedObjects count];
    NSLog(@"Numero=",numero);
    switch (section)
    {
        case 2 : return numero;
        case 3 : return 30;
        default : return 8;
    }
}

我确定,实体ToDoItems现在有1个对象(使用SQLite Manager检查),但NSLog显示Numero= 我的代码出了什么问题?

3 个答案:

答案 0 :(得分:2)

首先你的日志不正确,正如我在评论中所说的那样。

NSLog(@"numero = %d", numero);

然后你应该正确实现表视图的数据源方法。 e.g。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [[fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section {
    id  sectionInfo =
        [[fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

numero这里是[sectionInfo numberOfObjects]

有关详细信息,请查看NSFetchedResultsController tut,以及“核心数据编程指南”。这是你的参考手册。

答案 1 :(得分:1)

您实际上并未打印出NSLog语句中的数字

使用

NSLog(@"Numero=%d", numero)

答案 2 :(得分:0)

我不确定我是否完全理解你想要实现的目标,但如果你想要一个带有固定部分的UITableView和一些从Core Data填充的部分和其他硬编码的部分,也许就像侧边栏菜单一样,那么你需要做类似于以下。请注意,在下面的示例中,“任务和可交付成果”部分中的项目是使用fetchedResultsController从Core Data获取的(但是只需正常的提取就可以了,但我太懒了,无法删除fetchedResultsController代码!)。我所做的只是得到一个结果数组,所以我不使用任何委托方法。

这些部分在sectionsArray中定义,每个部分的项目都包含在单独的数组中,并存储在名为sectionMenus的字典中。

另请注意,当从Core Data加载数据时,我加载了一个临时菜单项(“正在加载,请稍候......”)(iCloud文件可能尚未下载数据)。

无论如何,请查看此链接中的视频,了解应用运行时此“菜单”的外观。

http://ossh.com.au/design-and-technology/software-development/uimanageddocument-icloud-integration/

http://ossh.com.au/design-and-technology/software-development/uimanageddocument-icloud-integration/when-to-enable-the-user-interface/

在tableViewController .h文件中添加sectionMenus字典和sectionsArray数组,如下所示

    @interface MenuViewController : BaseMenuViewController <NSFetchedResultsControllerDelegate> {
        NSArray *sectionsArray;
        NSMutableDictionary *sectionMenus;
        bool _isLoaded;
    }

    @property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
    @property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;

    @property (strong, nonatomic) NSString *entityName;

@end

现在在.m文件中,您需要执行以下操作:

#define MENU_PROJECT            @"Project"
#define MENU_TASKS              @"Tasks and Deliverables"
#define MENU_FINANCE            @"Finance"
#define MENU_QUALITY            @"Quality"
#define MENU_IT_SYSTEMS         @"IT Systems"
#define MENU_ADMIN              @"Administration"

#define SUBMENU_SCOPE              @"Scope"
#define SUBMENU_LOADING            @"Loading, please wait..."

@implementation MenuViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //[self.openingViewController setFilesName:self.filesName];
    //[self.openingViewController setFilesDate:self.filesDate];

    // If we get menu's from the database set this to YES
    _isLoaded = NO;

    sectionMenus = [[NSMutableDictionary alloc] init];
    sectionsArray = [[NSArray alloc] initWithObjects:MENU_PROJECT, MENU_TASKS, MENU_FINANCE, MENU_QUALITY, MENU_IT_SYSTEMS, MENU_ADMIN, nil];

    NSString * bundleID = [[NSBundle mainBundle] bundleIdentifier];

    if ([bundleID isEqualToString:@"au.com.ossh.iProject2FreeiPad"])
    {
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:SUBMENU_SCOPE, nil] forKey:MENU_PROJECT];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:SUBMENU_LOADING, nil] forKey:MENU_TASKS];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:@"Expenses", nil] forKey:MENU_FINANCE];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:@"Issues", nil] forKey:MENU_QUALITY];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:@"Applications", nil] forKey:MENU_IT_SYSTEMS];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:@"People", nil] forKey:MENU_ADMIN];
    } else {
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:SUBMENU_SCOPE, nil] forKey:MENU_PROJECT];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:SUBMENU_LOADING, nil] forKey:MENU_TASKS];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:@"Expenses", @"Ongoing Costs", @"Timesheets", nil] forKey:MENU_FINANCE];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:@"Issues", @"Risks", nil] forKey:MENU_QUALITY];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:@"Applications", @"Interfaces", nil] forKey:MENU_IT_SYSTEMS];
        [sectionMenus setObject:[[NSArray alloc] initWithObjects:@"People", @"Setup", nil] forKey:MENU_ADMIN];        
    }

    // Do any additional setup after loading the view.
    self.entityName = @"ProjectCategory";

    [self fetchedResultsController];

}

- (void)reload {
    NSArray *tadMenus = [self projectCategories];
    if (tadMenus) {
        _isLoaded = YES;
        [sectionMenus setObject:[[NSArray alloc] initWithArray:[self projectCategories]] forKey:MENU_TASKS];
    } else {
        _isLoaded = NO;
    }
}
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [self.tableView reloadData];
}
// Override this to set your own.
- (NSArray*)sortDescriptors
{
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"sortIndex" ascending:YES];
    NSArray *sortDescriptors = @[sortDescriptor];
    return sortDescriptors;
}

#pragma mark - Fetched results controller

- (NSFetchedResultsController *)fetchedResultsController
{
    /*
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    */

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:self.entityName inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

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

    [fetchRequest setSortDescriptors:[self 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:nil];
    aFetchedResultsController.delegate = self;
    _fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![_fetchedResultsController performFetch:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _fetchedResultsController;
}

- (NSArray*)projectCategories {
    //LOG(@"projectCategories called");
    int count=0;
    id <NSFetchedResultsSectionInfo> sectionInfo;

    if ([[[self fetchedResultsController] sections] count] > 0) {
        sectionInfo = [[[self fetchedResultsController] sections] objectAtIndex:0];
        count = [sectionInfo numberOfObjects];
    } else
        count = 0;
    //FLOG(@" %d categories found", count);
    if (count == 0) return nil;

    NSMutableArray *projectCategories = [[NSMutableArray alloc] initWithCapacity:count];

    for (NSManagedObject *item in _fetchedResultsController.fetchedObjects)
    {
        [projectCategories addObject:item];
        //FLOG(@" adding category %@", [item valueForKey:@"name"]);
    }

    return projectCategories;

}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return [sectionsArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return [[sectionMenus objectForKey:[sectionsArray objectAtIndex:section]] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    return [[sectionsArray objectAtIndex:section] description];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *simpleTableIdentifier = @"SimpleTableItem";
    static NSString *inactiveTableIdentifier = @"InactiveTableItem";
    UITableViewCell *cell;
    NSObject *menuItem = [[sectionMenus objectForKey:[sectionsArray objectAtIndex:[indexPath section]]] objectAtIndex:[indexPath row]];
    NSString *menu = [menuItem description];

    cell.textLabel.text = menu;

    return cell;
}