5
votes

I have a Company entity with about 20 fields and I'm wanting to use a grouped tableView with manually created section headers (ie: General, Financial, Misc.), but I am unsure of how to make Core Data understand how to treat these section headers and make them relate only to the data I want to show in these groups.

For example, name, logo, etc would go under General, budgets, cash would go under financial, etc.

Basically, I want to control what data from Core data gets put into each category and display it.

In the Core books sample there is this code:

/*
 The data source methods are handled primarily by the fetch results controller
 */

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


// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

But how do I make it understand that the sections aren't in Core data, but created manually?

2

2 Answers

1
votes

I've got an answer to my problem now, I do not know if its the correct approach, but it is working and would welcome comments.

Just to clarify what the problem was, and what I was trying to do.

I have a core data entity company with about 10 or so fields inside them, however rather than listing them all in one go, I wanted to group the outputted fields.

For example, I have about 6 fields relating to cash such as "cash", "marketingBudget", "seoBudget", etc and I wanted to group this data on the tableView, but the problem was I didn't know how to set up a relationship so that table.field.x belonged to group.x, and so on.

The answer I came to was to use a PLIST/dictionary that pretty much mirrors the structure of the core data entity; and assign the structure to the groups I want to display.

My dictionary looks like this;

(root)

->CompanyTpl (array)

--> Item 0 (Dictionary)

---> Section (String) = "General"

---> Children (Array ) ------> Item 0 (Dictionary)

----------> Key = "name"

----------> Value = "Company Name" ...

Where the Key would be a reference for Core Data to use and display its contents, if required.

Where the Value would be would to display at the cellForRowAtIndexPath.

So, in my code I basically went through the section (by which I mean tableView section) and then find the correlating children info from the PLIST; and get the Key/Value and use this as and when required.

Here is a cut down version of the code.

- (void)viewDidLoad {
    NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"CompanyTpl" ofType:@"plist"];
    self.companyDictionary = [[NSDictionary dictionaryWithContentsOfFile:plistPath] retain];

    // self.tableDataSource is a NSMutableArray
    self.tableDataSource = [self.companyDictionary objectForKey:@"CompanyTpl"];

    // Debugging info
    NSLog(@"Section = 0");

    NSLog(@"%@", [self.tableDataSource objectAtIndex:0]);

    NSLog(@"Section Name = %@", [[self.tableDataSource objectAtIndex:0] objectForKey:@"Section"]);


    NSArray *sectionChildren = [[self.tableDataSource objectAtIndex:0] objectForKey:@"Data"];

    NSLog(@"Section Children = %@", sectionChildren);
    NSLog(@"Count of Section Children = %d", [sectionChildren count]);


}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return ([self.tableDataSource count]);
}

// Section header
-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    NSString *title = nil;

    title = [[self.tableDataSource objectAtIndex:section] objectForKey:@"Section"];

    return title;
}


// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
NSInteger rows = 0;

    NSArray *sectionChildren = [[self.tableDataSource objectAtIndex:section] objectForKey:@"Data"];

    NSLog(@"Section Children = %@", sectionChildren);
    NSLog(@"Count of Section Children = %d", [sectionChildren count]);

    rows = [sectionChildren count];


    return rows;
}

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

    NSArray *sectionChildren            = [[self.tableDataSource objectAtIndex:indexPath.section] objectForKey:@"Data"];
    NSDictionary *sectionChildrenData   = [sectionChildren objectAtIndex:indexPath.row];

    //NSLog(@"Section Children data = %@", sectionChildrenData);

    NSString *scKey     = [sectionChildrenData objectForKey:@"Key"];
    NSString *scValue   = [sectionChildrenData objectForKey:@"Value"];

    NSLog(@"scKey = %@", scKey);

    // Grab the data from Core Data using the scKey



    static NSString *CellIdentifier = @"defaultCell";

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


        //cell.textLabel.text = @"test";

        cell.textLabel.text = scValue;
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

    }
    return cell;
}

The idea would be that I can use the KEY when referencing Core Data to grab its contents and display it on the tableView controller at cellForRowAtIndexPath cell.textLabel.text value.

One could go a little further in depth and have more info in the PLIST such as what the subtitle should be, etc.

Anyway, would welcome comments and thoughts.

Thanks.

0
votes

I have got a little closer to an answer, but I am still having trouble hooking up core data items so that they are in certain sections.

#pragma mark -
#pragma mark Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    //return [[fetchedResultsController sections] count];
    
    //NSLog(@"%d", [self.sectionArray count] );
    
    return 4;
}

// Section header
-(NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    NSString *title = nil;
    
    switch (section) {
        case 0:
            title = @"General";
            break;
        case 1:
            title = @"Finanical";
            break;
        case 2:
            title = @"Category A";
            break;
        case 3:
            title = @"Category B";
            break;
        case 4:
            title = @"Misc";
            break;
        default:
            break;
    }
    
    return title;
}



// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{
    /*
    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
     */
    
    NSInteger rows = 0;
    
    // The number of rows depend on the section
    switch (section) {
        case 0:
            rows = 2;
            break;
        case 1:
            rows = 3;
            break;
        case 2:
            rows = 4;
            break;
        default:
            break;
    }
    
    return rows;
}

What this does is manually create 4 sections, the names don't matter at the moment, and then I create a different number of rows for each section.

So far, so good.

The problem I'm having is making Core Data understand that in section0.row0 I want the textLabel to say the the company name etc.

I'm thinking that all of this has to be in a dictionary, laying-out the entire structure that I want, and the labels to display; and then in cellForRowAtIndexPath I display the array within the dictionary that I want.

ie:

[root] CompanyTpl (array)

--> Item 0 (dictionary)

-----> Category (string) = "General"

-----> Data (Array)

---------> Item 0 (Dictionary)

---------------> cdFieldName: name

---------------> display: "Company name"

Where cdFieldName is a reference to the field name within Core Data I want to display.

If there is an alternative way to do this, I'd be interested in finding out.

Thanks.