I've got a tableView in storybord and UISegmentedControl to populate the over mentioned table with with different data and different design. My problem is that numberOfRowsInSection meth doesn't react when I switch UISegmentedControl.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(self.segment.selectedSegmentIndex==0)
{
return [self.items count];
NSLog(#"Nominals: %d",self.items.count);
}
if(self.segment.selectedSegmentIndex==1)
{
return [self.coinageArr count];
NSLog(#"Coinage: %d",self.coinageArr.count);
}
//return 0; Complains about no return.
}
Well, NSLogs do not work while navigating. And how to return NSInteger in this case?
Thanx in advance.
EDIT: For shannoga
segment controller switch method:
-(IBAction)segmentValueChaged:(id)sender
{
switch (self.segment.selectedSegmentIndex)
{
case 0:
{
DBAccess *access=[[DBAccess alloc]init];
self.items=[access returnNominals:self.entityID nk:fromPeriod];
[access closeDataBase];
self.tableView.hidden=NO;
[self.tableView reloadData];
break;
}
case 1:
{
DBAccess *access=[[DBAccess alloc]init];
self.coinageArr=[access returnCoinage:fromPeriod period:self.entityID];
self.tableView.hidden=NO;
[self.tableView reloadData];
break;
}
}
}
The NSLog won't work because the return take effect before you get to this line and it will never be executed.
Change it to:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(self.segment.selectedSegmentIndex==0)
{
NSLog(#"Nominals: %d",self.items.count);
return [self.items count];
}
if(self.segment.selectedSegmentIndex==1)
{
NSLog(#"Coinage: %d",self.coinageArr.count);
return [self.coinageArr count];
}
//return 0; Complains about no return.
}
Can you show the method that you call when the UISegmentedControl is changed?
Pay attention that you don't need to set 2 if statements you could use else.
As #Ryan said you should use [tableview reloadData] on your UISegmentedControl change. Then it will be better if you change the self.items array in your valueChanged method and leave the numberOfRowsInSection with out a change so it will look like that:
- (void)valueChanged:(id)sender
{
if(self.segment.selectedSegmentIndex==0)
{
self.items = what ever
}else{
self.items = what ever
}
[tableview reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [self.items count];
}
Good Luck
After you change the value of the UISegmentedControl you need to update the table. You can do it easily with [tableView reloadData]; or you can use something like [tableView reloadSection:0 withTableViewAnimation:UITableViewRowAnimationAutomatic];
The best place to do this is probably in a valueChanged method for your control.
// Wherever you init your UISegmentedControl
segmentedControl addTarget:self selector:#selector(valueChanged:) forEvent:UIControlEventValueChanged];
- (void)valueChanged:(id)sender
{
[tableview reloadData];
}
Related
i try many thing but it displaying cells
i have add delegate and datasource
tableview.dataSouce =self;
tableview.Delegate = self;
func cell for row height
return 44;
i dont know why table view is not displaying
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
int count = (int)_dict_contact.count;
return count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
case 0:
{
NSArray *arr_email =[_dict_contact objectForKey:#"u_email"];
int count = (int)arr_email.count;
return count;
}
break;
case 1:
{
NSArray *arr_phone =[_dict_contact objectForKey:#"u_phone"];
return arr_phone.count;
}
break;
}
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MultipleContCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell = [[MultipleContCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
switch (indexPath.section) {
case 0:
{
NSArray *arr_email =[_dict_contact objectForKey:#"u_email"];
cell.detail_lbl.text =[arr_email objectAtIndex:indexPath.row];
return cell;
}
break;
case 1:
{
NSArray *arr_phone =[_dict_contact objectForKey:#"u_phone"];
cell.detail_lbl.text =[arr_phone objectAtIndex:indexPath.row];
return cell;
}
break;
}
return cell;
}
but after trying too much then also my cellForRowAtIndexPath not called
You need to call registerNib: forCellReuseIdentifier or registerClass:forCellReuseIdentifier for MultipleContCell inside viewdidload. For example:
[_yourTableView registerNib:[UINib nibWithNibName:#"MultipleContCell" bundle:nil] forCellReuseIdentifier:#"MultipleContCell"];
Check :
1) The numberOfSectionsInTableView is not returning 0.
2)UITableview frame is correct because cellForRowAtIndexPath would not be called is when the size or positioning of the table does not require any rows to be displayed.
Make sure that
numberOfSectionsInTableView returns value > 0
numberOfRowsInSection returns value > 0
UITableView frame > 0
You must declare your ViewController as UITableViewDelegate and UITableViewDataSource. Something like this:
#interface MyViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>
I have a UITableViewController that I'm building up in my application. This UITableViewController (SelectedLanguages) is called from another UITableViewController (ChooseLanguage) where there is a static list of languages for the user to select.
In the SelectedLanguages UITableViewController, I want to achieve the following:
2 Sections
The first section will have between 1 and 5 cells
The second section will always have 12 cells.
The number of cells in the first section is entirely dependent on which language the user chooses in the ChooseLanguage UITableViewController. For example, clicking on English will mean the first section in the SelectedLanguage UITableViewController will have 5 cells, but choosing French in the ChooseLanguage UITableViewController will mean the first section in the SelectedLanguage will only have 1 cell.
As mentioned, the second section will always have 12 cells in the SelectedLanguage.
I have designed this UITableViewController in Interface Builder. What I've seen is that only if the the Content is specified as Static Cells can you have multiple "sections".
Even if you set the Content to Dynamic and Grouped, I can't seem to find a way to determine sections other than in code.
The reason I'm defining this in Interface Builder is because section 1 and section 2 will need to have a very customised layout of the size of the cells, as well as the labels that go into each cell.
The content of the first section is not dynamic; it is static because while building this application, I'll know exactly how many cells there should be in the first section for each language, so in my head, it is correct to use a Static cell.
My question is, how can I achieve setting the number of cells in the top section, in code?
In the prepareForSegue of the ChooseLanguage, I could check the called cell title and then perform some action in the SelectedTransactions. The action to perform here is what I'm confused about.
I know there's the method - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section in the UITableView Data Source, but I'm not sure how and what to do with this with my particular situation.
Any guidance would be really appreciated.
My easiest answer for your question is below
in .m
import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *arraysection1;
NSMutableArray *arraysection2;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arraySection1 = [[NSMutableArray alloc]initWithObjects:#"One",#"Two",#"Three",#"Four",#"Five",nil];
arraySection2 = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5",nil];
}
#UITableView Delegate Methods
#UITableView DataSource Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//If you have 2 sections,
return 2;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//set row of two sections with condition
if(section==0)
{
return arraySection1.count;
}
else
{
return arraySection2.count;
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCellIdentifier = #"CellIndentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCellIdentifier];
}
if(indexPath.section==0)
{
cell.textLabel.text = [NSString stringWithFormat:#"%#",[arraySection1 objectAtIndex:indexPath.row]];
NSLog(#"The textLabel is-%#",cell.textLabel.text);
}
else
{
cell.textLabel.text = [NSString stringWithFormat:#"%#",[arraySection2 objectAtIndex:indexPath.row]];
NSLog(#"The textLabel is-%#",cell.textLabel.text);
}
return cell;
}
#UITableView Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section==0)
{
if(indexPath.row==0)
{
//Do whatever you want here
}
else if(indexPath.row==1)
{
//Do whatever you want here
}
else if(indexPath.row==2)
{
//Do whatever you want here
}
else if(indexPath.row==3)
{
//Do whatever you want here
}
else
{
//Do whatever you want here
}
}
else
{
if(indexPath.row==0)
{
//Do whatever you want here
}
else if(indexPath.row==1)
{
//Do whatever you want here
}
else if(indexPath.row==2)
{
//Do whatever you want here
}
else if(indexPath.row==3)
{
//Do whatever you want here
}
else
{
//Do whatever you want here
}
}
}
From what you are describing it sounds like your tableView should be dynamic.
You will have to handle this programmatically, forget about interface builder
Here is what you need:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;//2 Sections
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
switch (section) {
case 0:
//The first section will have between 1 and 5 cells
//Put the logic to return the correct number of cells
return 5;
break;
case 1:
//The second section will always have 12 cells.
return 12;
break;
default:
break;
}
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
switch (indexPath.section) {
case 0:
[[cell textLabel] setText:#"same title section 1"];
break;
case 1:
[[cell textLabel] setText:#"same title section 2"];
break;
default:
break;
}
return cell;
}
I have two sections in my UITableView populated by predicate filtering of a single array as their datasource. When the predicate filtered arrays have items in them, the headers are drawn (colored) correctly and are at the correct positions. The colors are set in willDisplayHeaderView.
Note, this is NOT a UITableViewController, but a UITableView that is part of a more complex view.*
New items can be added to the table with an add (+) button.
When I delete items from a section until it has 0 items, the header disappears correctly.
When I add a new item to one of these empty (and now invisible) sections, the header is drawn and named correctly, but it's not colored correctly and appears slightly overlapping the section above it (or in the case of the first/0th section, it appears under the table top so you can't see half the text).
It's almost like willDisplayHeaderView isn't getting called when a section not previously there is now added because it's datasource now has data.
Here are my methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return kSectionCount;
}
and
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
switch (section) {
case kIncompleteActivitiesSection:
return [[_activitiesArray filteredArrayUsingPredicate:_predIncomplete] count];
case kCompleteActivitiesSection:
return [[_activitiesArray filteredArrayUsingPredicate:_predComplete] count];
default:
return 0;
}
}
and
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
// return the section names
switch (section) {
case kIncompleteActivitiesSection:
if ([[_activitiesArray filteredArrayUsingPredicate:_predIncomplete] count] > 0) {
return #"Upcoming Activities";
} else {
return nil;
}
case kCompleteActivitiesSection:
if ([[_activitiesArray filteredArrayUsingPredicate:_predComplete] count] > 0) {
return #"Completed Activities";
} else {
return nil;
}
default:
return 0;
}
}
and
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
// set header text Color
UITableViewHeaderFooterView *header = (UITableViewHeaderFooterView *)view;
[header.textLabel setTextColor:[UIColor whiteColor]];
// set header background color
header.backgroundView = [UIView new];
header.backgroundView.backgroundColor = _colorSchemeColor;
header.backgroundView.alpha = 1.0;
}
When you change your _activitiesArray you have to reload the section(s) that are affected. The section headers are not updated automatically, in my experience.
[self.tableView beginUpdates];
//Update your data model here
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
You can substitute whichever row animation style you prefer.
I have a tableView with with some sections and each section with some rows.Every row has a favorite button.If the button is clicked the row should get added to the favourites section.
(which is initially empty).
I have written some code.but the problem is it is working in iOS 5 simulator and getting crashed in iOS 6 simulator with Invalid tableView update error.
Can someone tell me where the problem is.?
-(void)moveRowToFavourites:(id)sender{
UIButton *button = (UIButton *)sender;
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
[tempArray addObject:[NSIndexPath indexPathForRow:favouritesArray.count inSection:0]];
[favouritesArray insertObject:cell.textLabel.text atIndex:favouritesArray.count];
[[self tableView] beginUpdates];
[[self tableView] insertRowsAtIndexPaths:(NSArray *)tempArray withRowAnimation:UITableViewRowAnimationFade];
[[self tableView] endUpdates];
}
EDIT
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(searching){
return [self.searchResults count];
}
else{
if ([[arrayForBool objectAtIndex:section] boolValue]) {
if(section == 0){
return favouritesArray.count;
}else{
NSString* key = [self.proCategoriesArray objectAtIndex:section - 1];
NSArray *aArray = [sectionContentDict valueForKey:key];
return aArray.count;
}
}
return 1;
}
}
You just should call the following:
[favouritesArray addObject:cell.textLabel.text];
[tableView reloadData];
Make sure you implemented this function:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
switch(section){
case 0:
return favouritesArray.count;
//Your other sections have to placed here, too
default:
return 0;
}
}
Then your tableView should update itself. The problem is that you insert whole cells, but you just have to insert data in your array. Hope it helps!
It seems like your data source is returning 0 as number of sections and rows. You are not correctly inserting/deleting rows, when you insert a new row, data source methods get called again, and if for instance you try to insert an object in a way that the row count will be 4, and data source tableView:numberOfRowsInSection: returns 3, you get an exception because you're trying yo add more objects that what data source promises.
When you try to update a table view all these data source methods get called again:
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView;
- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath;
You must ensure that they return correct values. I suspect that you aren't even implementing them.
Edit
The problem is that you are just inserting a new object in favouritesArray, but this doesn't affect the number of rows returned by tableView:numberOfRowsInSection:. There you aren't returning favouritesArray.count, the exception is due to the fact that tableView:numberOfRowsInSection: returns a lower number than the rows that the table view should have.
In your case I think that you don't even need to call insertRowsAtIndexPaths:, you can do everything with your data source:
-(void)moveRowToFavourites:(id)sender {
UIButton *button = (UIButton *)sender;
UITableViewCell *cell = (UITableViewCell *)button.superview.superview;
[favouritesArray insertObject:cell.textLabel.text atIndex:favouritesArray.count];
[[self tableView]reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return favouritesArray.count;
}
In tableView:cellForRowAtIndexPath: you should return a cell that has an object fetched form favouritesArray as text.
I have a table view which has 10000+ cells. and there is a segment button (All/Favorite) on the top.
this is the call back for the segment:
- (IBAction)call_segment:(id)sender {
[self.tableView beginUpdates];
[self.tableView reloadData];
[self.tableView endUpdates];
}
for favorite page, even when there are no favorite items, I simply set the cell height to be 0. But in this way, I created all 10000+ cells on screen.
if 'all' is selected, the table works just fine since cells have normal height and only some of them are dequeued on screen.
Here is my code:
//if it's not in favorite, just hide it by setting the height to be 0
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([self isFavorite]) {
int uniqueId = [self uniqueIdWithIndexPath:indexPath];
if ([DATABASE isFavoriteWithMode:self.mode uniqueId:uniqueId] == NO) {
return 0;
}
}
return 60;
}
//in table view datasource:
//I think the problem is, when setting the height to be 0, all the cells are allocated. I set the cell to be hidden but still takes memory. any way to deal with it?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL isFavorite = [DATABASE isFavoriteWithMode:self.mode uniqueId:[self uniqueIdWithIndexPath:indexPath]];
if ([self isFavorite] && isFavorite == NO) {
cell.hidden = YES;
return [[UITableViewCell alloc] init];
}
else {
cell.hidden = NO;
ListCell *cell = (ListCell *)[tableView dequeueReusableCellWithIdentifier:CELL_LIST];
Datum *datum = [DATABASE datumWithMode:self.mode uniqueId:[self uniqueIdWithIndexPath:indexPath]];
BOOL isRead = [DATABASE isReadWithMode:self.mode uniqueId:[self uniqueIdWithIndexPath:indexPath]];
cell.indexLabel.text = [NSString stringWithFormat:#"%d", datum.uniqueId];
cell.titleLabel.text = [NSString stringWithFormat:#"%#", datum.q];
return cell;
}
}
Note: I dont wanna just show the favorite cells, since the logic is way too complex. I am using sqlite, but i dont think database performance is the problem, since the 'all' tab works just fine.
The reason i wanted to just set the height to be 0 is the simple implementation of cell numbers
- (BOOL)isFavorite {
return self.segment.selectedSegmentIndex == 1;
}
- (IBAction)call_segment:(id)sender {
[self.tableView beginUpdates];
[self.tableView reloadData];
[self.tableView endUpdates];
}
#define NUM_SECTIONS 15
- (int)numRows {
return [DATABASE numberOfDataForModes:self.mode];
}
- (int)numSections {
if ([self numRows] % NUM_SECTIONS > 0) {
int numSections = [self numRows] / [self numRowsPerSection];
if ([self numRows] % [self numRowsPerSection] > 0) {
numSections++;
}
return numSections;
}
return NUM_SECTIONS;
}
- (int)numRowsPerSection {
return [self numRows] / NUM_SECTIONS;
}
- (int)numRowsInLastSection {
if ([self numRows] % ([self numSections] - 1) > 0) {
return [self numRows] % ([self numSections] - 1);
}
else {
return [self numRowsPerSection];
}
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
int start = section * [self numRowsPerSection] + 1;
int end = start + [self numRowsPerSection] - 1;
if (end > [self numRows]) {
end = [self numRows];
}
return [NSString stringWithFormat:#"From %d to %d", start, end];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
NSMutableArray *titles = [NSMutableArray arrayWithCapacity:[self numSections]];
int start = 1;
while (start < [self numRows]) {
NSString *title = [NSString stringWithFormat:#"%d", start];
[titles addObject:title];
start += [self numRowsPerSection];
}
return titles;
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return index;
}
- (int)uniqueIdWithIndexPath:(NSIndexPath *)indexPath {
int uniqueId = indexPath.row + 1 + indexPath.section * [self numRowsPerSection];
return uniqueId;
}
- (NSIndexPath *)indexPathWithUniqueId: (int)uniqueId {
int section = (uniqueId - 1) / [self numRowsPerSection];
int row = uniqueId - 1 - [self numRowsPerSection] * section;
return [NSIndexPath indexPathForRow:row inSection:section];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([self isFavorite]) {
int uniqueId = [self uniqueIdWithIndexPath:indexPath];
if ([DATABASE isFavoriteWithMode:self.mode uniqueId:uniqueId] == NO) {
return 0;
}
}
return 60;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == [self numSections] - 1) {
return [self numRowsInLastSection];
}
return [self numRowsPerSection];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self numSections];
}
Instead of hiding the cells why dont you just return 0 from the datasource method
– tableView:numberOfRowsInSection:
You can just make use of the isFavorite value within this function and return 0 if there it is NO.
You got it already. The problem is the size of 0 of non-favorite cells. That contradicts the idea of reusabel cells. You will have thousands of cells on the screen, although invisible but existing and therefore resource consuming. Better think of a smarter way of doing that. Your data source delegate (view controller I guess) should only return the number of non-fav cells and therefore cellForRowAtIndexPath should only provide those cells of non-fav items. Plus cellForRowAtIndexPath should actually reuse the cells which I do not see in your code sniplet.
No matter how much you try having 10,000 views onscreen is not going to be the solution to your problem. You need to change your code structure such that you can return 0 for the tableView:numberOfRowsInSection: delegate when the favourites tab is chosen.
Any other 'solution' is an attempt to hack an alternative together, but this will not work and is bad code practice anyway. Implement it properly, by responding to the delegates properly.
I've given up making both table section separated. the logic is way too complicated.
I guess there is no way to save memory even when you hide the cells. Thank you guys for your input. you are all correct.
It's actually not that bad since favorite table are typically not that long. just one section with all entries.