【问题标题】:Why is NSFetchedResultsController assigning fetched objects to multiple UITableView sections?为什么 NSFetchedResultsController 将获取的对象分配给多个 UITableView 部分?
【发布时间】:2015-09-03 19:18:07
【问题描述】:

在我的另一个question 中,关于在Core Data 支持的UITableView 中添加插入行,我提到我的NSFetchedResultsController 将它获取的每个对象分配给我的UITableView 中的单独部分。我认为这只是默认行为,但 Marcus S. Zarra 说我的控制器配置或数据源委托方法可能有问题。我承认,我的代码感觉有点像弗兰肯斯坦,其中的部分来自 Apple 文档和大量教程。这是我的第一个程序,也是我第一次使用 Core Data,所以请温柔一点;)

我的table view controller的header如下:

    #import <UIKit/UIKit.h>
    #import "RubricAppDelegate.h"


    @interface ClassList : UITableViewController {
        NSMutableArray *classList;
        NSFetchedResultsController *fetchedResultsController;
        NSManagedObjectContext *managedObjectContext;

}

@property(nonatomic,retain) NSMutableArray *classList;
@property(nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property(nonatomic, retain) NSManagedObjectContext *managedObjectContext;

- (IBAction) grade:(id)sender;

@end

我的实现文件包含一堆虚拟测试数据。我包括在内,以防我使用不正确的方法来实例化 Core Data 对象。基本上,我想知道我的 NSFetchedResultsController 是否应该将我的对象(在本例中为 myClass 的实例)返回到单独的部分中。如果是这样,我在做什么来制造这个问题?

目前的最终目标是让我能够在表格顶部添加一个插入单元格(我知道将它放在底部是“标准的”,但我喜欢它在应用程序中的外观反过来做)。您会注意到我的-tableView:editingStyleForRowAtIndexPath: 设置要插入的第 0 节的单元格样式,但当然我需要弄清楚如何在单元格 1 而不是单元格 0 开始列出 myClass.classTitle(这就是为什么我要确定是否将每个对象分配到自己的部分是正常的)。

这是我的实现文件:

#import "ClassList.h"
#import "ClassRoster.h"
#import "RubricAppDelegate.h"
#import "Student.h"
#import "myClass.h"


@implementation ClassList

@synthesize classList;
@synthesize fetchedResultsController;
@synthesize managedObjectContext;

#pragma mark -
#pragma mark View lifecycle


- (void)viewDidLoad {
    [super viewDidLoad];

    self.editing = YES;

    RubricAppDelegate *appDelegate = (RubricAppDelegate *)[[UIApplication sharedApplication] delegate];
    managedObjectContext = [appDelegate managedObjectContext];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"myClass" inManagedObjectContext:managedObjectContext];
    NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
    [request setEntity:entity];

    //test data
    myClass *newClass = (myClass *) [NSEntityDescription insertNewObjectForEntityForName:@"myClass" inManagedObjectContext:managedObjectContext];
    newClass.classTitle = @"UFDN 1000";
    NSNumber *ID = [NSNumber numberWithInt:1];
    newClass.classID = ID;

    Student *newStudent = (Student *) [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:managedObjectContext];
    newStudent.classID = ID;
    newStudent.studentName = @"Andy Albert";
    newStudent.studentUsername = @"albera";
    [newClass addStudentsObject:newStudent];

    newStudent.classID = ID;
    newStudent.studentName = @"Bob Dole";
    newStudent.studentUsername = @"doleb";
    [newClass addStudentsObject:newStudent];

    newStudent.classID = ID;
    newStudent.studentName = @"Chris Hanson";
    newStudent.studentUsername = @"hansoc";
    [newClass addStudentsObject:newStudent];

    myClass *newClass2 = (myClass *) [NSEntityDescription insertNewObjectForEntityForName:@"myClass" inManagedObjectContext:managedObjectContext];
    newClass2.classTitle = @"UFDN 3100";
    ID = [NSNumber numberWithInt:2];
    newClass2.classID = ID;

    newStudent.classID = ID;
    newStudent.studentName = @"Danny Boy";
    newStudent.studentUsername = @"boyd";
    [newClass2 addStudentsObject:newStudent];

    newStudent.classID = ID;
    newStudent.studentName = @"James Matthews";
    newStudent.studentUsername = @"matthj";
    [newClass2 addStudentsObject:newStudent];

    newStudent.classID = ID;
    newStudent.studentName = @"Aaron Todds";
    newStudent.studentUsername = @"toddsa";
    [newClass2 addStudentsObject:newStudent];


    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"classID" ascending:YES];
    NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
    [request setSortDescriptors:sortDescriptors];
    [sortDescriptor release];
    NSError *error;

    fetchedResultsController = [[NSFetchedResultsController alloc]
                                               initWithFetchRequest:request 
                                               managedObjectContext:self.managedObjectContext
                                               sectionNameKeyPath:@"classTitle" cacheName:nil];

    [fetchedResultsController performFetch:&error];

    UIBarButtonItem *gradeButton = [[UIBarButtonItem alloc] 
                                    initWithTitle:@"Grade" 
                                    style:UIBarButtonItemStylePlain
                                    target:self
                                    action:@selector(grade:)];
    self.navigationItem.rightBarButtonItem = gradeButton;

    [gradeButton release];

}

- (IBAction) grade:(id)sender {

}

#pragma mark -

#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    NSLog(@"Number of sections = %d", [[fetchedResultsController sections] count]);
    return ([[fetchedResultsController sections] count]);

}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    id <NSFetchedResultsSectionInfo> myClass = [[fetchedResultsController sections] objectAtIndex:section];
    NSLog(@"Number of classes = %d", [myClass numberOfObjects]);

    return [myClass numberOfObjects];

}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

        myClass *theClass = [fetchedResultsController objectAtIndexPath:indexPath];
        NSLog(@"Class name is: %@", theClass.classTitle);
        cell.textLabel.text = theClass.classTitle;
    }

    return cell;
}

    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (indexPath.section == 0) {
            return UITableViewCellEditingStyleInsert;
        }
        else return UITableViewCellEditingStyleDelete;
    }


    // Override to support editing the table view.
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

        if (editingStyle == UITableViewCellEditingStyleDelete) {
            myClass *result = (myClass *)[fetchedResultsController objectAtIndexPath:indexPath];
            [managedObjectContext deleteObject:result];
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];

        }   
        else if (editingStyle == UITableViewCellEditingStyleInsert) {

        }   
    }

    #pragma mark -
    #pragma mark Table view delegate

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        // Navigation logic may go here. Create and push another view controller.
        /*
         <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
         // ...
         // Pass the selected object to the new view controller.
         [self.navigationController pushViewController:detailViewController animated:YES];
         [detailViewController release];
         */
    }


    #pragma mark -
    #pragma mark Memory management

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

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

    - (void)viewDidUnload {
        // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
        // For example: self.myOutlet = nil;
    }


    - (void)dealloc {
        [classList release];
        [super dealloc];
    }


    @end

我的 RubricAppDelegate 与用于设置 Core Data NSManagedObjectContext、NSPersistentStoreCoordinator 等的 Apple 文档基本相同。但是,如果您认为其中可能存在问题,请告诉我,我会发布它。

编辑:我忘了提到我知道每个对象被分配到不同部分的两个原因。

1) NSLog(@"Number of sections = %d", [[fetchedResultsController sections] count]); 内的 -numberOfSectionsInTableView: 返回我拥有的 myClass 对象的数量。

2) 如果我将-numberOfSectionsInTableView: 设置为返回 1,我的表格将只显示一个对象,而将其余对象删除。

【问题讨论】:

    标签: uitableview core-data nsfetchedresultscontroller


    【解决方案1】:

    您有部分是因为您在初始化 FRC 时通过为 sectionNameKeyPath: 传递一个非 Nil 值来告诉获取的结果控制器创建它们。

    变化:

    fetchedResultsController = [[NSFetchedResultsController alloc]
                                               initWithFetchRequest:request 
                                               managedObjectContext:self.managedObjectContext
                                               sectionNameKeyPath:@"classTitle" cacheName:nil];
    

    ...到:

    fetchedResultsController = [[NSFetchedResultsController alloc]
                                               initWithFetchRequest:request 
                                               managedObjectContext:self.managedObjectContext
                                               sectionNameKeyPath:nil cacheName:nil];
    

    ...这些部分将消失。否则,FRC 将为商店中classTitle 属性的每个值创建一个部分。如果每个myClass 实例具有不同的classTitle 值,则每个实例在tableview 中都有自己的部分。

    【讨论】:

    • 这很简单 :) 感谢 TechZen!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多