Push view controller logic error - iphone

Im wondering if someone can please tell me what am I missing. I got a tableview with two sections, but when I tap onto anything on section 2, content from section 1 cells is loaded.
Thanks in advance.
here is my didselectrowatindexpath:
UIViewController *targetViewController = [[views objectAtIndex:indexPath.row] objectForKey:#"controller"];
[[self navigationController] pushViewController:targetViewController animated:YES];
if (indexPath.section == 0)
[partA objectAtIndex:indexPath.row];
else
[partB objectAtIndex:indexPath.row];
[targetViewController release];
}

In your tableView:didSelectRowAtIndexPath: method, you may not be accounting for the section; i.e. you're pulling a UIViewController from the views array using indexPath.row, when you should probably also be using indexPath.section as a qualifier. It's hard to give a better answer without seeing more of your view controller.

You may consider to use following code instead of your if statement.
UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:indexPath];
Also remove the release because you did not retain or allocate it.
But honest: I do not understand what you want to do. What do you mean by "loaded"? Loaded where?

You haven't provided it but my guess is that you should override didSelectRowAtIndexPath method and check the owner of the selecting cell:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
if ( tableView == _tableView1){
//Do something
}
else if ( tableView == _tableView2){
//Do something different
}
else return;

Related

Modifying static cells outside cellForRowAtIndexPath without creating new cells

So I get that its typically frowned upon to modify a cell outside of the cellForRowAtIndexPath but here is what I have:
I have a static table that is used as an index of questions (1-33). Each row has a question on it and a detail disclosure indicator. All of this is manually entered in on the stoyboard.
I have a file that lists each question and some properties such as if the question has been answered.
When this screen loads (viewDidAppear) I want to check if each of these questions have been loaded and if so switch the detail indicator to a checkmark.
Now this works, for the first 5 cells. If I go to a question and come back, then even more cells are checked (even if the questions have not been answered). Is this undefined behavior because I am accessing it outside of cellForRowAtIndexPath?
Here is the code I'm using to access and change the cell:
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (question1Answered)
{
UITableViewCell *cell1 = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:3]];
[cell1 setAccessoryType:UITableViewCellAccessoryCheckmark];
}
}
Again, it does work for the first 5 elements, then the rest will not change no matter what I do. Then if I go to a question and return it shows more with it selected. Strange behavior...
EDIT: I just noticed that the above code works but it only updates the cells that are currently on the screen. So if I scroll down, leave and come back all the visible cells will have the check mark. Is there a way to force a refresh of all the cells, even if they aren't visible?
Thanks for any and all help...
-David
This is similar to another question I answered few days ago. See stackoverflow.com/a/11770387/1479411
Use delegate method. Put any code that modifies the cell content and [self.tableView reloadData] in the delegate method after returning from the other view controller.
You should not update cell from viewDidAppear.
Instead you should reload data from viewDidApeear.
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (question1Answered)
{
//This will call your tableview's delegate for visible cells
[self.tableView reloadData];
}
}
And inside cellForRowAtIndexPath, you should take a decision to assign accessory type.
U should first update your model then update your UI according to the model state.
For example if your model is an array of Question object, and each question has some hasBeenAnswered boolean.
Then the only thing u should do in viewDidAppear is to call [self.tableView reloadData], this will update your table view because cellForRowAtIndexPath will be called and set the cells according to your model state.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// configure the cell according to your model state
Question *question = [self.questions objectAtIndex:indexPath.row];
// check if this question has been answered
if (question.hasBeenAnswered) {
// if yes - set a checkmark
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
else {
// if not - set to none (or whatever u want)
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
return cell;
}

How to dynamically update your UITableView when a button is pressed?

I'm stuck with a seemingly very simple app that I'm trying to develop
Basically, I have a UITable, and two buttons: red/blue
When a button is pressed, a row with corresponding title of that button is append to the table
I'm overwhelmed by how complicated UITableView has to be implemented (datasource, delegate, resuable identifier, etc)
Can anyone help me out with this, preferably show me detailed codes
For my Buttons, I have something like this
- (IBAction)buttonPressed:(UIButton *)sender{
NSString *item = sender.currentTitle;
[self.cellArray addObject:item];
[self.myTable reloadData];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.cellArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"The Table Cell";
self.myTableCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (self.myTableCell == nil) {
self.myTableCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
self.myTableCell.textLabel.text = [self.cellArray objectAtIndex:indexPath.row];
return self.myTableCell;
}
Since you are learning this..i will post a simple solution.
Make add a member variable NSMutableArray *cellArrays;
initialize it in your viewDidLoad
in buttonPressed check;
if([#"red" isEqualToString:[YourButton titleForState:UIControlStateNormal]])
{
[self.cellArrays addObject:#"red"];
}
else
{
[self.cellArrays addObject:#"blue"];
}
[self.YOURTABLEVIEW reloadData];
Now in your table view datasource method
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.cellArrays.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//in between your code;
YOURCELL.textlabel.text = [self.cellArrays objectAtIndex : indexpath.row];
}
Try this ..
I'd recommend subclassing UITableViewController, then override the dataSource and delegate methods and you should be good to go. Going straight to UITableView is more complicated without any obvious benefits.
You may not be using Core Data, but I still recommend this lecture because it hooks up a TableViewController and works great - all code included. Check it out:
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/node/289
The lectures in iTunes U explain everything further.
Enjoy,
Damien
I wanted to add that "One more thing, the compiler shows a warning says no reusable identifier. what exactly is that?" above...
His answer is correct, but to get rid of that compiler warning...
The tableviewcell of your tableview has to have an identifier. In IOS 5, in your storyboard, highlight the TableViewCell in your TableView, and enter a value in the Identifier. This must match the value in your code of the cell that you are creating.

Pushing viewController from a tableview that is inside a viewController not working

I am having an issue pushing my view controller from a tableview that was dropped into a viewController, and not a TableViewController.
I have found a thread on here with a solution here
pushViewController is not pushing
The problem is.. I have done his solution and my view still does not push. I have connected my tableview via ctrl+drag to the view controller and set both the dataSource and delegate. In the post i mentioned, they say the solution was to 'create a referencing outlet from the tableview to the view controller.' But I don't exactly know what that means. So help with that would be good as well. I have followed this tutorial and am stuck on step 9 obviously.
The line of code not triggering is
[self.navigationController pushViewController:facility animated:YES];
My code is as follows...
viewTable methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"list Size: %#",list);
return [list count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
CustomerListData *customer = [self.list objectAtIndex:indexPath.row];
cell.textLabel.text = customer.facilityName;
// cell.textLabel.text = #"Detail";
return cell;
}
-(void)setValue:(NSMutableArray*)array
{
//NSMutableArray *newArray = [[NSMutableArray alloc] init];
list = array;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
FacilityMissionListViewController *facility = [self.storyboard instantiateViewControllerWithIdentifier:#"facilityMissionList"];
[self.navigationController pushViewController:facility animated:YES];
//UINavigationController* navController = self.navigationController;
}
the very last commented out line is there to check if navigationcontroller was null. It is not.
From what I have gathered the issue here lies in the fact the table view is inside the view controller and its not a "tableviewcontroller." This method apparently works if that is the case, but some other steps must be taken if not.. but I don't know them.
Thanks in advance.
It sounds like your NavigationController is not set up correctly. Could you post the code that sets it up?
Put a :
NSLog(#"%#", self.navigationController);
in your didSelectRowAtIndexPath method and you'll see if the method is being called and if the navigationController is nil. It might be one of this cases.
Otherwise make sure that the FacilityMissionListViewController is not nil either.

UITableview - tableView:didDeselectRowAtIndexPath: method not working properly?

In my application i am using UITableview. In that delegate method didselectrow if i done any operation cant happen just.
For example i have 3 rows in tableview
if i select 1 row (indexPath.row==0) nothing will happen
if again select 2 row (indexPath.row==1) now it is Logging in console indexPath.row ==0 which is previous value.
if again select 1 row then its logging its previous value indexPath.row=1.
Why this going like .
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomerInfoViewController *customer = [[EquipmentViewController alloc]initWithNibName:#"CustomerInfoViewController" bundle:nil];
EquipmentViewController *equpment = [[EquipmentViewController alloc]initWithNibName:#"EquipmentViewController" bundle:nil];
ContactsViewController *contacts = [[ContactsViewController alloc]initWithNibName:#"ContactsViewController" bundle:nil];
if(indexPath.row == 0)
{
NSLog(#"one %d",indexPath.row);
[detailsView addSubview:customer.view];
}
if(indexPath.row == 1)
{
NSLog(#"two %d",indexPath.row);
[detailsView addSubview:equpment.view];
}
if(indexPath.row == 2)
{
NSLog(#"three%d",indexPath.row);
[detailsView addSubview:contacts.view];
}
}
Please anyone help me.
Thanks in advance.
You've implemented didDeselectRowAtIndexPath method, not didSelectRowAtIndexPath as intended
Wrong method implementation as Vladimir said. use didSelectRowAtIndexPath

cellForRowAtIndexPath not called; sections returns 1 and rows returns 4

After parsing JSON data in a Data class, I set the UIViewController's NSArray *headlines property in a fillArrays method of the same Data class. In the viewDidAppear method of my UIViewController, I call reloadData on my UITableView. numberOfSectionsInTableView fires and returns 1, then numberOfRowsInSection fires and returns an array count of 4 (for 4 strings in the array). However, control never gets to cellForRowAtIndexPath and I'm having the hardest time understanding why, especially since I have valid sections and rows. The cells are all visible.
I've added the UITableViewDataSource and UITableViewDelegate protocols to the UIViewController interface and set the UITableView's delegate and dataSource to self in viewDidLoad (which also is verified by the row and section count methods being called).
I'm wondering if it has something to with me reinitializing the UIViewController in Data.m in order to set its properties.
In Data.m:
- (void)fillArrays:(NSArray *)jsonObjs {
NSLog(#"fillArrays");
HeadlinesRootViewController *hrvc = [[HeadlinesRootViewController alloc] init];
hrvc.headlines = [self getJsonValuesForKey:#"headline" inArrayOfObjects:jsonObjs];
[hrvc viewDidAppear:NO];
}
In ViewController.m:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"viewDidLoad");
// Table view
headlineTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 180, self.view.bounds.size.width, 300) style:UITableViewStylePlain];
[headlineTableView setDelegate:self];
[headlineTableView setDataSource:self];
// Temporary
self.headlines = [[NSMutableArray alloc] initWithObjects:#"headline1", #"headline2", #"headline3", #"headline4", nil];
[self.view addSubview:headlineTableView];
self.headlineTableView = headlineTableView;
[headlineTableView release];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"viewdidappear");
NSLog(#"headlines: %#", self.headlines); // Returns an array of 4 headlines
if( [self.headlines count] != 0 ){
[self.headlineTableView reloadData];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"numberOfSectionsInTableView: 1");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"numberOfRowsInSection: %d", [self.headlines count]);
return [self.headlines count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cellForRowAtIndexPath");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.text = [[NSString alloc] initWithFormat:#"%#", [self.headlines objectAtIndex:indexPath.row]];
return cell;
}
In fillArrays, you create another view controller - but you never do anything with it or its view, you would never see that view. You would never call viewDidAppear manually either, that happens automatically when a view controllers view is displayed (ONLY in the context of a navigation controller though).
Normally the flow is, you create a view controller and either add that view as a subview of a current view, or push it as a new window via a navigation controller. I'm pretty sure your whole issue is that they table is never added to a view anyone actually sees, so the table calls the other methods but never calls cellForRow because its layoutSubviews code is simply not being called.
Have you added your tableView to the view of UIViewController?
It happened to me, and when I added this
[self.view addSubview:table];
[table release];
then cellForRowAtIndexPath started working.
For Google's sake:
If tableView:numberOfRowsInSection returns zero for whatever reason tableView:cellForRowAtIndexPath will not get called because there are no rows to call it for.
Check to make sure that the tableView delegate and dataSource are pointed to the viewController
I cannot see anything wrong with the code as-is, have you verified with breakpoints that cellForRow is never reached (even though I see you have a log statement)?
Also I would try just for a sanity check to return "1" explicitly in rowsInSection, and hardcode a string in the cell you are returning in cellForRow.
If all else fails, create a new table view controller from the XCode templates and put your calls in there - then when that works, work backwards to why your code does not.
Also, it would be good to see your viewDidLoad setup code (add to answer above please).
if you're setting the delegate and datasource at viewDidLoad, then that may be the source of your bug. Can you set the datasource and delegate in init?
I'm not sure that you add your UITableView as subview to UIViewController.view. This was my approach anyway.
In this approach, I found execution did not get into cellForRowAtIndexPath until I sent UIViewController.view to the back after adding UITableView as subview.
Getting this far was only part of the problem. At this point, it seemed that my other view controllers no longer respond to touch events. I found that when I also add the UITableView as a subview to the rootViewController, all my views got the appropriate touch events.
Thank you so much pxl. When I move the UITableView initialization from viewDidLoad to:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil"
it works perfectly when ever I make delete or update some rows the UITableView gets reloded to my UIView.
Swift version
Add self.table.layoutIfNeeded() and then self.tableView.reloadData()