Why does Section data reset each time? - ios

I'm quite new to iOS development (as you'll see from my code below). I like to help myself learn new languages by manipulating existing code to do something different. I've hit a bit of a blank with this one though. At the end of each section in a table view, the data it is using resets and it starts again, instead of carrying on. Can anyone tell me where the fault lies here please?
#import "RootViewController.h"
#import "DataController.h"
#import "DetailViewController.h"
#import "Play.h"
#implementation RootViewController
#synthesize dataController;
#synthesize play;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.title = NSLocalizedString(#"Plays", #"Master view navigation title");
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Only one section.
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
/*
The number of rows varies by section.
*/
NSInteger rows = 0;
switch (section) {
case 0:
rows = 3;
break;
case 1:
rows = 1;
break;
case 2:
rows = 2;
break;
default:
break;
}
return rows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {
static NSString *CellIdentifier = #"PlayCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Get the object to display and set the value in the cell.
Play *playAtIndex = [dataController objectInListAtIndex:indexPath.row];
cell.textLabel.text = playAtIndex.title;
return cell;
}
// Section header titles
#pragma mark -
#pragma mark Section header titles
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:
(NSInteger)section {
NSString *secttitle = nil;
switch (section) {
case 0:
secttitle = NSLocalizedString(#"Comedy", #"Comedy section title");
break;
case 1:
secttitle = NSLocalizedString(#"Action", #"Action section title");
break;
case 2:
secttitle = NSLocalizedString(#"Drama", #"Drama section title");
break;
default:
break;
}
return secttitle;
}
// End of section header titles
#pragma mark -
#pragma mark Table view selection
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
/*
When a row is selected, the segue creates the detail view controller as the destination.
Set the detail view controller's detail item to the item associated with the selected
row.
*/
if ([[segue identifier] isEqualToString:#"ShowSelectedPlay"]) {
NSIndexPath *selectedRowIndex = [self.tableView indexPathForSelectedRow];
DetailViewController *detailViewController = [segue destinationViewController];
detailViewController.play = [dataController objectInListAtIndex:selectedRowIndex.row];
}
}
#end
Thanks for your replies so far. The Detail view works fine, and judging by your feedback so far it appears it's because this code isn't being evaluated, but I can't seem to work out where to incorporate it in the master view.
NSString *cellText = nil;
switch (indexPath.section) {
case 0:
cellText = play.date;
break;
case 1:
cellText = play.genre;
break;
case 2:
cellText = [play.characters objectAtIndex:indexPath.row];
break;
default:
break;
}
cell.textLabel.text = cellText;
return cell;

Because you're only using the indexPath.row to get your cell content. Your data model should also consider the indexPath.section:
Play *playAtIndex = [dataController objectInListAtIndex:indexPath.row];
cell.textLabel.text = playAtIndex.title;
i.e. you have a one-dimensional data model...

This line:
Play *playAtIndex = [dataController objectInListAtIndex:indexPath.row];
only takes into account the current indexPath's row, which also resets to zero at the beginning of each section. You'll need to use an array of arrays or otherwise account for the rows in previous sections to get the correct index.

Related

Some overrided UITableView methods not being called after app relaunch

All my overrided UITableView methods are being called when I first run the program. But if I terminate the app in the simulator and re-launch from the simulator home screen, some of the overridden methods are not being called (ex. commitEditingStyle) and instead the preset method is called.
Is there a reason why they wouldn't be called after app relaunch but would work after a clear run?
My table code:
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// set toolbar delegate for editing toolbar style
self.aToolbar.delegate = self;
numberOfSections = 1; // for editing: initial number of sections
// for testing
NSLog(#"%#", ptrBookmarks1);
// load bookmarks segment bar with user's most recent segment selections
bookmarksSegmentControl.selectedSegmentIndex = selectedBookmarksSegmentIndex;
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
//allow row selection during editing.
//if the "Add New Song" row is selected we can trigger an insert.
//rather than forcing the using to click the (+) icon directly
self.aTableView.allowsSelectionDuringEditing = YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
// selected table data
NSMutableArray *tableData;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
tableData = ptrBookmarks1;
break;
case 1: // Bookmarks 2 selected
tableData = ptrBookmarks2;
break;
case 2: // My Songs selected
tableData = ptrMySongs;
break;
}
if ([self isEditing]) // the current view is in editing mode, return count + an extra row
return [tableData count] + 1;
else // return count
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
// selected table data
NSMutableArray *tableData;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
tableData = ptrBookmarks1;
break;
case 1: // Bookmarks 2 selected
tableData = ptrBookmarks2;
break;
case 2: // My Songs selected
tableData = ptrMySongs;
break;
}
//if number of rows is greater than the total number of rows in the data set
//and this view is in editing mode.
//Initialize the cell for "Add New Song"
//there will be an extra row once SetEditing: is called
if(indexPath.row >= tableData.count && [self isEditing]){
cell.textLabel.text = #"Add New Song";
//cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; // display arrow accessory
}
else {
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
//cell.accessoryType = UITableViewCellAccessoryNone; // hide arrow accessory
}
return cell;
}
//VIEW CONTROLLER METHOD: IMPORTANT
//this is a method of the view controller
//if we use apple's editing button as follows:
//self.navigationItem.rightBarButtonItem = self.editButtonItem
//then this method will be called automatically for us.
//if we are using a button callback or similar method,
//then we need to call setEditing: manually on the view
-(void) setEditing:(BOOL)editing animated:(BOOL)animated{
//wrap our code in an if statement
//only run the code if we are not swipe deleting a row.
//if we were called due to a swipeDelete action, ignore it
if(isSwipeDeleting == NO){
//call parent
[aTableView setEditing:editing];
[super setEditing:editing animated:animated];
// selected table data
NSMutableArray *tableData;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
tableData = ptrBookmarks1;
break;
case 1: // Bookmarks 2 selected
tableData = ptrBookmarks2;
break;
case 2: // My Songs selected
tableData = ptrMySongs;
break;
}
//if editing mode
if(editing){
//batch the table view changes so that everything happens at once
[self.aTableView beginUpdates];
//for each section, insert a row at the end of the table
for(int i = 0; i < numberOfSections; i++){
//create an index path for the new row
NSIndexPath *path = [NSIndexPath indexPathForRow:tableData.count inSection:i];
//insert the NSIndexPath to create a new row. NOTE: this method takes an array of paths
[self.aTableView insertRowsAtIndexPaths:#[path] withRowAnimation:UITableViewRowAnimationAutomatic];
}
//animate the changes now
[self.aTableView endUpdates];
}else{
//batch the table view changes so that everything happens at once
[self.aTableView beginUpdates];
//for each section, insert a row at the end of the table
for(int i = 0; i < numberOfSections; i++){
//create an index path for the new row
NSIndexPath *path = [NSIndexPath indexPathForRow:tableData.count inSection:i];
//insert the NSIndexPath to create a new row. NOTE: this method takes an array of paths
[self.aTableView deleteRowsAtIndexPaths:#[path] withRowAnimation:UITableViewRowAnimationAutomatic];
}
//animate the changes now
[self.aTableView endUpdates];
}
}
}
//DELEGATE METHOD:
//this method will be called for every row and allows us to set the
//editing syle icon(Delete,Insert)
-(UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
// selected table data
NSMutableArray *tableData;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
tableData = ptrBookmarks1;
break;
case 1: // Bookmarks 2 selected
tableData = ptrBookmarks2;
break;
case 2: // My Songs selected
tableData = ptrMySongs;
break;
}
// Detemine if it's in editing mode
if (self.editing) {
//use the + icon(add icon) on row
//if this is the additional row created in setEditing:animated:
if(indexPath.row >= tableData.count){
return UITableViewCellEditingStyleInsert;
}
else {
//use the delete icon on this row
return UITableViewCellEditingStyleDelete;
}
}
else
return UITableViewCellEditingStyleNone;
}
//handle the deletion/insertion
//this method is called when the delete or insert icon has been press.
//we should update our dataSource by inserting or removing the selected INDEX
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// selected table data
NSMutableArray *tableData;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
tableData = ptrBookmarks1;
break;
case 1: // Bookmarks 2 selected
tableData = ptrBookmarks2;
break;
case 2: // My Songs selected
tableData = ptrMySongs;
break;
}
if (editingStyle == UITableViewCellEditingStyleDelete) { // the delete icon was clicked
// delete pre-test
NSLog(#"Array before delete: %#", tableData);
NSLog(#"Directory before delete: ");
[self readDirectoryContents];
// if deleting a song or its pages that's in view, switch view to previous MySong if exists, otherwise About page/a blank page
////////insert code here////////
// remove file and its annotations from directory (if deleting from My Songs)
if (tableData == ptrMySongs) {
[self deleteImportedSongsheet:tableData[indexPath.row]];
}
//remove row from tableData
[tableData removeObjectAtIndex:indexPath.row];
//remove the row in the tableView
[self.aTableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
// delete post-test
NSLog(#"Array after delete: %#", tableData);
NSLog(#"Directory after delete: ");
[self readDirectoryContents];
[self.aTableView reloadData];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) { // the insert icon was clicked
/*
//add a new row to the datasource
[tableData addObject:#"New Icon"];
//insert a row in the tableView because the plusIcon was clicked.
[self.aTableView insertRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];*/
self.editing = false; // turn off editing
// ---SEGUE TO SONG IMPORT OPTIONS TABLE---
SongImportView *songImportView =
[[SongImportView alloc]
initWithNibName:#"SongImportView" bundle:nil];
// forward the My Songs array
songImportView.ptrMySongs = ptrMySongs;
// set delegate
songImportView.delegate = self;
// push SongImportView
[self.navigationController pushViewController:songImportView animated:YES];
[SongImportView release];
}
}
//if we are in editing mode we do not want to perform Seque Transition
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
if ([identifier isEqualToString:#"MyDetailView"] && [self isEditing]) {
return NO;
}
return YES;
}
//this method is called when the user swipes to delete a row.
- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath{
isSwipeDeleting = YES;//user just swipe to delete a row
}
//when the user cancel the swipe or click the delete button
//this method is call
- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath{
isSwipeDeleting = NO;//swipe to delete ended. No longer showing the DELETE button in cell
}
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return NO;
//return YES;
}
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
// MUST CHANGE canMoveRowAtIndexPath TO ENABLE THIS
NSString *item;
// selected table data
NSMutableArray *tableData;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
tableData = ptrBookmarks1;
break;
case 1: // Bookmarks 2 selected
tableData = ptrBookmarks2;
break;
case 2: // My Songs selected
tableData = ptrMySongs;
break;
}
item = [[tableData objectAtIndex:fromIndexPath.row] retain];
[tableData removeObjectAtIndex:fromIndexPath.row];
[tableData insertObject:item atIndex:toIndexPath.row];
[item release];
}
#pragma mark - Table view delegate
//DELEGATE METHOD:
//the user selected a row
//In order for the user to perform an INSERTION action on a row,
//they have to click the + icon icon. We can implement this method
//so that they can click anywhere on the "Add New Song" to add a new row
//tableView.allowsSelectionDuringEditing = YES; must be set
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//deselect the selected row with animatiion
[self.aTableView deselectRowAtIndexPath:indexPath animated:YES];
// selected table data
NSMutableArray *tableData;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
tableData = ptrBookmarks1;
break;
case 1: // Bookmarks 2 selected
tableData = ptrBookmarks2;
break;
case 2: // My Songs selected
tableData = ptrMySongs;
break;
}
//if the selected row was the "Add New Song" row call tableView:commitEditingStyle:
//to add a new row
if (indexPath.row >= tableData.count && [self isEditing]) {
[self tableView:tableView commitEditingStyle:UITableViewCellEditingStyleInsert forRowAtIndexPath:indexPath];
}
else { // otherwise do regular table item selection
[self.delegate didTapBookmarksTable:[tableData objectAtIndex:indexPath.row]];
}
}
// to scroll the table to the top row that was last viewed
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
NSIndexPath *iP;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
if ([ptrBookmarks1 count] > 0) { // make sure that there is something in the table before scrolling to it, otherwise will crash
iP = [NSIndexPath indexPathForRow:bookmark1listPositionRow inSection:bookmark1listPositionSection];
[aTableView scrollToRowAtIndexPath:iP atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
break;
case 1: // Bookmarks 2 selected
if ([ptrBookmarks2 count] > 0) { // make sure that there is something in the table before scrolling to it, otherwise will crash
iP = [NSIndexPath indexPathForRow:bookmark2listPositionRow inSection:bookmark2listPositionSection];
[aTableView scrollToRowAtIndexPath:iP atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
break;
case 2: // My Songs selected
if ([ptrMySongs count] > 0) { // make sure that there is something in the table before scrolling to it, otherwise will crash
iP = [NSIndexPath indexPathForRow:mysongslistPositionRow inSection:mysongslistPositionSection];
[aTableView scrollToRowAtIndexPath:iP atScrollPosition:UITableViewScrollPositionTop animated:NO];
}
break;
}
}
// remember the top row that was last viewed
- (void)viewDidDisappear:(BOOL)animated {
NSIndexPath *ip;
switch (bookmarksSegmentControl.selectedSegmentIndex) {
case 0: // Bookmarks 1 selected
if ([ptrBookmarks1 count] > 0) { // make sure that there is something in the table before scrolling to it, otherwise will crash
ip = [[aTableView indexPathsForVisibleRows] objectAtIndex:0];
bookmark1listPositionSection = ip.section;
bookmark1listPositionRow = ip.row;
}
break;
case 1: // Bookmarks 2 selected
if ([ptrBookmarks2 count] > 0) { // make sure that there is something in the table before scrolling to it, otherwise will crash
ip = [[aTableView indexPathsForVisibleRows] objectAtIndex:0];
bookmark2listPositionSection = ip.section;
bookmark2listPositionRow = ip.row;
}
break;
case 2: // My Songs selected
if ([ptrMySongs count] > 0) { // make sure that there is something in the table before scrolling to it, otherwise will crash
ip = [[aTableView indexPathsForVisibleRows] objectAtIndex:0];
mysongslistPositionSection = ip.section;
mysongslistPositionRow = ip.row;
}
break;
}
}

Updating A Specific Row In UITableView Without Reloading The Whole Table

I would like to update the the text of a label in tableview without reloaddata.
I try ((uilabel *)[self.tableview viewWtihTag:10]).text = Newstring
but its not work.
Is it correct? or have another solution?
Using this method - (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation is correct. However, you should keep track of the value to be loaded in every row in each cell, and then access them every time a row is reloaded when the user scrolls the table.
Here is a sample:
#interface ViewController ()<UITableViewDelegate, UITableViewDataSource>
#property NSMutableArray *labelValueListForSection0;
#property NSMutableArray *labelValueListForSection1;
#property NSMutableArray *labelValueListForSection2;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_labelValueListForSection2 = [[NSMutableArray alloc] initWithObjects:#"value1", #"value2", #"value3", nil];
}
- (void)changeAnItem
{
[_labelValueListForSection2 setObject:#"ChangedValue" atIndexedSubscript:1];
[_table reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:1 inSection:2]] withRowAnimation:UITableViewRowAnimationNone];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"SimpleTableItem";
UITableViewCell *tableCell = [tableView dequeueReusableCellWithIdentifier:identifier];
if(tableCell == nil)
{
tableCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
switch(indexPath.section)
{
case 0:
tableCell.textLabel.text = #"Test";
break;
case 1:
tableCell.textLabel.text = #"Test";
break;
case 2:
tableCell.textLabel.text = [_labelValueListForSection2 objectAtIndex:indexPath.row];
break;
case 3:
tableCell.textLabel.text = #"Test";
break;
case 4:
tableCell.textLabel.text = #"Test";
break;
default:
break;
}
return tableCell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
#end
As you can see, I am keeping track of the value of each row and I am storing them inside an array. In my case, I have an array of values for each row for a specific section. So that when this method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
is called, it will fetch the value that should be assigned to that row.
In case you don't know, iOS is reusing each table cell for better performance and better memory management. So, if you encounter cases such as why is a value of one of my rows is duplicated in other rows, it is because that instance of tableCell is reused in other rows.
So, in order to make sure that each time a cell is loaded, and the value should be correct. You have to keep track of the value for each row and reassign it to that cell each time it is reloaded.
Hope this will help you solve your problem.
Try to reload particular cell of table ...
NSIndexPath* rowToReload = [NSIndexPath indexPathForRow:3 inSection:0];
[myUITableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:rowToReload, nil] withRowAnimation:UITableViewRowAnimationNone];
And add code to change text in cellForRowAtIndexPath:
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
Use this method. This helps you to solve your problem

Using a static UITableViewController to create two sections with the first section having a non-static number of cells

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;
}

How to link individual cell in uitableview to distinct URL?

I currently have two separate arrays of titles in my uitablview. Each array is grouped in it's own section. Eg. Section 1 (item1, item2, item3) Section 2(item1, item2, etc). I would like to link each cell to a certain wordpress post. How would I do this? I have linked below all of my code below the viewdidload method which contains the arrays.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return numberOfSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
case manualSection:
return [self.manual count];
case interviewSection:
return [self.interviews count];
default:
return 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
switch (indexPath.section)
{
case manualSection:
cell.textLabel.text = [self.manual objectAtIndex:indexPath.row];
break;
case interviewSection:
cell.textLabel.text = [self.interviews objectAtIndex:indexPath.row];
break;
default:
cell.textLabel.text = #"Not Found";
}
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
switch (section) {
case manualSection:
return #"Manual";
break;
case interviewSection:
return #"Interviews";
break;
default:
return 0;
}
}
Create a model with the properties you need (title, link)
Update arrays (manuals, interviews) with models, and not strings
Implement the -tableView:didSelectRowAtIndexPath: function in the class you are presenting to us, to access the list at the index you need; then get the model and access the link
NSURL *url = [NSURL URLWithString:#"http://www.stackoverflow.com/"];
if( ![[NSWorkspace sharedWorkspace] openURL:url] )
NSLog(#"Failed to open url: %#",[url description]);

Static Cells - Hiding using the heightforRowatIndexPath method

Hi guy I'm trying to hide some of the rows in section 1 (Second section) depending on what type of feedback the user has selected:
I'm using static cells but at the moment nothing is being removed when I select one of the options in the TypeVC. There are no errors at the moment but having a guess I think its something to do with the logical operators I'm using in the switch statement. Sorry for dumping my code but as I'm very new to IOS I don't know what exactly you guys would need to see.
[1]
if (variable == (1|2|3)){}
I'm used to Java and I use this kind statement quite frequently as it saves writing. Is this how to do it in objective-c?
[2]
Where and how have I gone wrong here trying to get the cells to dissapear?
FeedbackTableViewController:
#import "FeedbackTableViewController.h"
#import "TypeTableViewController.h"
#interface FeedbackTableViewController ()
#property NSInteger index;
#end
#implementation FeedbackTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated{
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (NSIndexPath *) tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Type: %i",_type);
if (indexPath.section == 0 && indexPath.row == 0)
[self performSegueWithIdentifier:#"showTypeVC" sender:self];
return indexPath;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
TypeTableViewController *tvc = [segue destinationViewController];
tvc.indexchoosen = _index;
}
//- (UITableViewCell *)tableView:(UITableView *)tableView
// cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//
// UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
//
// if (indexPath.row==0) cell.textLabel.text = _typeString;
// else if (indexPath.row)
//
// return cell;
//}
- (CGFloat) tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"section: %i row:%i",indexPath.section, indexPath.row);
if (indexPath.section == 1) {
switch (_type) {
case 0:
if (indexPath.row==(2|3|4))return 0;
break;
case 1:
if (indexPath.row==(0|1|4))return 0;
break;
case 2:
if (indexPath.row==(0|1|2|3))return 0;
break;
case 3:
return 0;
break;
case 4:
return 0;
break;
case 5:
return 0;
break;
default:
return 0;
break;
}
}
return 43;
}
- (IBAction)unwindtypeVC:(UIStoryboardSegue *)segue { }
#end
TypeTableViewController:
#import "TypeTableViewController.h"
#import "FeedbackTableViewController.h"
#interface TypeTableViewController ()
#end
#implementation TypeTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_typeoptions = #[#"Routing Issues",
#"Wrongly Labelled Location",
#"Missing Location",
#"Comment on Useability",
#"Suggestions",
#"General Feedback"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 6;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.typeoptions[indexPath.row];
return cell;
}
- (NSIndexPath *)tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
_indexchoosen = indexPath.row;
return indexPath;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSString *string = _typeoptions[_indexchoosen];
FeedbackTableViewController *fvc1 = [segue destinationViewController];
fvc1.typeString.text = _typeoptions[_indexchoosen];
fvc1.type = _indexchoosen;
}
#end
I'm open to better ideas on achieving what I want to achieve also so if you would consider telling me a more efficient way of doing this I would be grateful. I know delegates might be an option however I'm not confident with them yet and would thought this would be easier for me.
For [1], try this and see it yourself:
int test = 3;
if(test == (1 | 2))
NSLog(#"_MEH_");
Since it's bitwise OR operation, 0010 | 0001 equals to 0011, which is equal to 3. Hence, I would not advise you to use an operation like that. (If that's not intentional, of course).
For [2], you should use deleteRowsAtIndexPaths:withRowAnimation: call for UITableView in order to delete rows.
For example;
[self.tableView beginUpdates];
NSIndexPath* rowToDelete = [NSIndexPath indexPathForRow:0 inSection:0]; // For showing purposes only.
NSArray* indexArray = [NSArray arrayWithObjects:rowToDelete, nil];
[self.tableView deleteRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationMiddle];
[self.tableView endUpdates];
Also, don't forget to update your data source accordingly. You may want to remove some objects from
self.typeoptions
array.
P.S: Another addition, you should also change tableView:numberOfRowsInSection: since there will be less rows than 6.
I actually managed to use this method of changing the row heights to 0.
In order to do it effectively I had to to remove the placeholder/any initial text in the rows that I didn't want shown. This required some storyboard connections which you will see named as _feedbackText _startLocation etc. When a user selected a new row, they would perform a segue to the original feedback form and therefore the viewDidAppear was called. I used this to call the [self.tableView reloadData]. Originally the change in the variable _type would not actually change anything but the heightForRowAtIndexPath is recalled when the data is reloaded.
I'm sure that using the delete row at indexPath would have worked also but I wanted to store the information that the user may have typed before they changed the type of feedback.
The New Method:
- (CGFloat) tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSInteger i = indexPath.row;
if (indexPath.section == 1) {
switch (_type) {
case 0:
_startLocation.placeholder = #"Start Location:";
_destination.placeholder = #"Destination:";
_locationName.placeholder = #"";
_correctName.placeholder = #"";
_missingLocation.placeholder = #"";
if (i==2||i==3||i==4) return 0;
break;
case 1:
_startLocation.placeholder = #"";
_destination.placeholder = #"";
_locationName.placeholder = #"Location Name:";
_correctName.placeholder = #"Correct Name:";
_missingLocation.placeholder = #"";
if (i==0||i==1||i==4)return 0;
break;
case 2:
_startLocation.placeholder = #"";
_destination.placeholder = #"";
_locationName.placeholder = #"";
_correctName.placeholder = #"";
_missingLocation.placeholder = #"Missing Location:";
if (i==0||i==1||i==2||i==3)return 0;
break;
case 3:
return 0;
break;
case 4:
return 0;
break;
case 5:
return 0;
break;
default:
_startLocation.placeholder = #"";
_destination.placeholder = #"";
_locationName.placeholder = #"";
_correctName.placeholder = #"";
_missingLocation.placeholder = #"";
if (i==0||i==1||i==2||i==3||i==4)return 0;
break;
}
} else if (indexPath.section==2 && indexPath.row==2) return 240;
else if (indexPath.section==0 && indexPath.row==0) return 40;
return 30;
}
This will essentially hide but not get rid of the information in the text fields. This is very useful if you want to the keep any information the user typed in.
I hope this helps anyone trying to hide rows in a grouped static table view controller.

Resources