I have a problem with UITableView sections. I'm using NSFetchedResultsController to populate table and I've provided sectionNameKeyPath: on initialization.
Basiclly I have a table view with one section but when user taps on cell it is changing one core data attribute and should create second section. I think I've accomplished this but...
When I tap on the first cell it creates new section above (this is how it should be) but when my first tap is on another cell it creates section at the botton of table view. You can preview this on screenshots below:
Here are some Table View delegate methods from my app:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[_fetchedResultsController sections] count];
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[[_fetchedResultsController sections] objectAtIndex:section] name];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id sectionInfo = [[_fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
And my question is: How to manually provide section order?
For this example solution was pretty straight - adding one NSSortDescriptor to existing one in NSFetchedResultsController sort descriptors array.
So now, fetched data is firstly sorted by section and then it is sorted alphabetically.
Related
I am using NSFetchedResultsController in my project along with core data. I am able to fetch all the objects from the database. I am displaying them in a sectioned table view. I want to display the total number of rows in each section as the header of the section table view. I am not getting any kind of help for this. I have tried a lot but don't know how exactly to set it . Any kind of help is appreciable.
Something like the following should work:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSInteger numberOfRows = [[[self.frc sections] objectAtIndex:section] numberOfObjects];
UITableViewHeaderFooterView *sectionHeaderView = [[UITableViewHeaderFooterView alloc] init];
sectionHeaderView.textLabel.text = [NSString stringWithFormat:#"Total objects %d", numberOfRows];
return sectionHeaderView;
}
The trick is getting the right section out of the NSFetchedResultsController and calling the numberOfObjects method on it. The sections in an NSFetchedResultsController are proxy objects that conform to the NSFetchedResultsSectionInfo delegate.
I have created a Universal Master Details application. I used Storyboard for the IPad and iPhone. I am actually making an HTTP request to retrieve the required data that will be presented in the master tableview. I reload the tableview data from the requestFinished method.
- (void)requestFinished:(ASIHTTPRequest *)request {
NSString *responseString = [request responseString];
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
conversationList = [responseString JSONValue];
[dataControllerSingleton setConversationList:conversationList];
[self.tableView reloadData];
}
I store the returned data in dataControllerSingleton which has an NSMutableArray property called conversationList.
In the numberOfRowsInSection, I print out the number of objects in the section based upon the fetchedResultsController. I also print out the number of values in my NSMutableArray conversationList. In numberOfSectionsInTableView I print out the number of sections.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
NSLog(#"Number OF Objects in section %lu",(unsigned long)[sectionInfo numberOfObjects]);
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
NSLog(#"ConversationList count %lu",(unsigned long)[dataControllerSingleton.conversationList count]);
return [sectionInfo numberOfObjects];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"Number of sections: %d",[[self.fetchedResultsController sections] count]);
return [[self.fetchedResultsController sections] count];
}
So, when I use NSLog to see how many section and rows I have I get
Number of Objects in section 2
ConversationList count 46
Number of Sections 1
In my cellForRowAtIndexPath I am adding the cell text from my NSMutableArray
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"ConversationCell"];
[self configureCell:cell atIndexPath:indexPath];
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
cell.textLabel.text = [dataControllerSingleton.conversationList objectAtIndex:indexPath.row];
return cell;
}
So, with this setup, I see two values in the master view for both iPhone and iPad. When I select either one of these values in master view, I am taken to the detail view (which is just empty for now). This works without any errors for the two rows that are presented.
If I change numberOfRowsInSection to return the number of values in my NSMutableArray
return [self.conversationList count];
I run into errors.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];
NSLog(#"Number OF Objects in section %lu",(unsigned long)[sectionInfo numberOfObjects]);
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
NSLog(#"ConversationList count %lu",(unsigned long)[dataControllerSingleton.conversationList count]);
//return [sectionInfo numberOfObjects];
return [self.conversationList count];
}
On iPhone simulator, I am presented with the 46 values in the master view. I can select any one of them and I am presented with the (empty) detail view. On the iPad simulator, if I select either one of the first two cells, I am presented with the (empty) detail view as expected. However, when I select any value beyond the first two, I get the following error;
Terminating app due to uncaught exception 'NSRangeException', reason: '*** - [_PFBatchFaultingArray objectAtIndex:]: index (2) beyond bounds (2)'
*** First throw call stack:
(0x19a5012 0x17cae7e 0x19a4deb 0x156941a 0x15e9511 0x42fe9 0x4ae285 0x4ae4ed 0xeb85b3 0x1964376 0x1963e06 0x194ba82 0x194af44 0x194ae1b 0x249b7e3 0x249b668 0x3feffc 0x40e0d 0x2ac5)
libc++abi.dylib: terminate called throwing an exception
Any assistance would be greatly appreciated. Thanks in advance.
Tim
If you are using more than one section (which it looks like you are) then delegate method
tableView:(UITableView *)tableView cellForRowAtIndexPath:
should really be handling this.
You also seem to be mixing the use of NSFetchedResultsController to work out the number of sections and rows, but then using the property self.conversionList to return the number of rows. But for which section. If you want to use Core Data then instead of using a singleton with an array, cache the data from your web server into a core data table and use that in your
- (NSFetchedResultsController *)fetchedResultsController
method.
Also you are mixing the use of self.conversionList &
ConversationDataController *dataControllerSingleton = [ConversationDataController sharedInstance];
dataControllerSingleton.conversationList
are they both the same?
Please add libz.dylib into your project . It can be added in the Build phases tab. There you have link with Binarry libraries section . Click '+' symbol and add libz.dylib to your project
Anything I missed in the following code? I can create a list but the list is array x26 times (26x section) in the UITableView. A list shown, but the section title is only point to 'A'
arr_indexpeople > An array of A,B,C,D,E.....Z
arr_completeArray > An array of a list of people
Thank you.
return [arr_indexpeople objectAtIndex:section]
You are returning objectAtIndex 0 in titleForHeaderInSection. Change it to-
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [arr_indexpeople objectAtIndex:section]
}
The datasource method will get called for every section to load, so give the dynamic index of a section as input variable for arr_indexpeople as shown below.
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [arr_indexpeople objectAtIndex:section]
}
I'm using Core Data and an NSFetchedResults controller to populate a UITableViewCell (plain style) in my app. The TableView has 3 sections, each with a viewForHeaderInSection and a viewForFooterInSection. The user will be entering items that will be put in each section.
When one of the sections has no items in it, it completely disappears. I'm wondering if it would be possible to make it so if a section is empty, it would display a new cell that would say "no entries" or something like that (maybe with a UIImageView or another view?), which would then go away if a new item was put into that section.
Does anyone know how to accomplish this?
Here's the code for my data source.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [[self.fetchedResultsController sections] count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}
Also, the section itself gets removed from the TableView when it has no rows, so how could I make it so the "no entries" cell gets added to the correct section?
If the section don't appear in the table view, it isn't returning from the fetch results, despite the fact you said you have 3 sections.
You can return it manually by:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
Then
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects] == 0){
return 1;
} else {
return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}
}
In your cellForRowAtIndexPath: test for empty..
if ([[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects] == 0){
cell.textLabel = #"No Entries";
}
Just a idea.
EDIT: Be careful, if you try to catch a index that isn't returned by the fetch, your app can crash.
You need to modify your numberOfRowsInSection function to check if there are no real rows for that section, and return 1 if that is the case (instead of 0).
Then, in the cellForRowAtIndexPath, check if you have data for that section, and just create your "no entries" cell when you see that you don't.
Hi
I'd like to pass an NSInteger to a tableView controller and then use it to set a badge.
In this case, the NSInteger I'd like to pass is the number of rows in a tableView, returned with Core Data (numberOfRows).
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSInteger numberOfRows = 0;
if ([[fetchedResultsController sections] count] > 0) {
id NSFetchedResultsSectionInfo sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
numberOfRows = [sectionInfo numberOfObjects];
}
return numberOfRows;
}
How can I declare another NSInteger and then pass it to a tableView controller?
Thanks,
Matthew
It sounds like you may need two fetched results controllers in the second table view controller. The first FRC would manage the table itself and the second would calculate the existing number of rows in the first table's data.
You would have to assign the second tableview controller as the delegate for both FRC and then in the delegate methods test which controller fired a change and take the appropriate action.