iphone (objective-c) accessory modification error - iphone

I have one last problem that is killing me.
I am playing around with an older project which used the tableView:accessoryTypeForRowWithIndexPath method, of which i am trying to rewrite the app without it.
I have deleted the tableView:accessoryTypeForRowWithIndexPath method, but my solution isnt working just yet.
The problem is that now when I press the 'Edit' button on my DetailViewController View, the 'editing' accessory types dont show.
Below is my actual code, and I have also included the project file for this, because I am desperate for a solution that works.
My question is, what code do I have to change, to get the accessory to change, and no other effects. (I know the RootViewController works, but how can i get the DetailViewController table to do the same?)
Regards, #norskben
Project File Download: Get it here.
setEditing
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.navigationItem setHidesBackButton:editing animated:animated];
[tableView reloadData];
}
cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tblView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
cell.editingAccessoryType = UITableViewCellAccessoryCheckmark;
}
switch(indexPath.section) {
case 0:
cell.textLabel.text = coffeeObj.coffeeName;
break;
case 1:
cell.textLabel.text = [NSString stringWithFormat:#"%#", coffeeObj.price];
break;
}
return cell;
}
Project File Download: Get it here.

In your setEditing:animated: method you are doing two things that you are really not supposed to do. Reloading the table data there makes no sense. And if you have to change the buttons in your tab bar manually then you have not set them up properly. The system takes care of that for you. If you have properly setup an edit button then you don't even manually have to call setEditing:animated: actually.
I think you should review some UITableView sample code.

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

reloaddata doesnt seem to be working

I may be using it incorrectly but i think i have it right. I load data into my UITableViewController like so.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CoCoachAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
switch (indexPath.section) {
case 0:
[cell.textLabel setText:#"Click to add new rower"];
cell.textLabel.textAlignment = UITextAlignmentCenter;
break;
case 1:
[cell.textLabel setText:[[appDelegate teamRoster]objectAtIndex:indexPath.row]];
break;
}
return cell;
}
And everything works fine, i then push the user to a different viewController and allow them to enter their name into a text field. I take their name and add it into the same array that populated my UITableViewController, and from the UITableViewController i call:
[self.tableView reloadData];
But nothing happens. If i check my array i can see that it has the correct number of objects, and their name is the last entry, but the tableview remains unchanged...
I was thinking maybe i just dont know how to use reloadData, but from what i have been reading elsewhere this should be working.
Any thoughts?
Your crash is due to the fact that you are doing
NSLog(#"%#",[[appDelegate teamRoster] count]);
when you should be doing
NSLog(#"%d",[[appDelegate teamRoster] count]);
Using %# sends the objec the message description, which does not work for ints (or floats or BOOLs).
The NSLog crashes because you are using the wrong formatter type (#"%#"), it should be:
NSLog(#"%d",[[appDelegate teamRoster] count]);
Other than that, where is reloadData being called from? Make sure it's happening on the Main thread.

My UITable is re-using cells when it shouldn't!

I have a UITableViewController which has two sections. The first section shows a single cell with centered text, saying Add a new Slide. The second section show the current slides.
When a user taps on the Add a new slide cell, a new UITableVeiwController is pushed onto the stack that shows an editor. If the user saves the new slide (by tapping save), the cell is added to the data source and the editor is popped from the stack.
I have two problems:
When the editor is popped, if a cell was deleted before Add a new slide was tapped, the old cell shows up instead of the new one. Popping the UITableViewController (by tapping the automatically generated back button) fixes this, but I'd like this to not happen at all. (Originally, popping the table did not update after popping the editor, so I added [self.tableView reloadData]; to the viewDidAppear method.)
After a certain number of slides, the last slide on the list becomes the Add a new slide cell. I know that the data is being entered properly because another part of the app, which uses the same data source, updates correctly. The table supports editing in the second section, and when you swap the order of the cells, it behaves correctly behind the scenes, but the wrong cell is still there.
What could be going on?
Here's some of my code:
Note that as I was gearing to post my code, I noticed a mismatch of the braces. The check for cell==nil seems to encompass the second part of the code which determines the content of the cells. This fixes the label of the cells in the second section of the table, but the style is still wrong. I've since fixed the code, but the original is posted here.
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
if ([indexPath section] == 0 ) {
cell = [[[MBTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}else if([indexPath section] == 1){
cell = [[[MBTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
if ([indexPath section] == 0) {
[cell.textLabel setTextAlignment:UITextAlignmentCenter];
[cell.textLabel setText:#"Add a New Slide"];
}else if([indexPath section] == 1){
NSArray *storedViewsInfo = [[NSArray alloc] initWithArray:[kSettings arrayForKey:#"views"]];
if ([[[storedViewsInfo objectAtIndex:[indexPath row]] valueForKey:#"type"] isEqualToString:#"announcement"]) {
[cell.detailTextLabel setText:#"Custom Announcement"];
[cell.textLabel setText:[[[storedViewsInfo objectAtIndex:[indexPath row]] valueForKey:#"info"] valueForKey:#"text"]];
}
[storedViewsInfo release];
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
}
return cell;
}
Without seeing the code, first thing that comes to mind is checking if you've given your custom cells different identifiers in your - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; method?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier1 = #"CellIdentifier1";
static NSString *Cellidentifier2 = #"CellIdentifier2";
if (indexPath.section == kAddSlideSection) {
CustomCell *cellType1 = (CustomCell*) [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
...
} else {
CustomCell *cellType2 = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
...
}
}
Also it might be worth considering implementing a delegate method that gets called when your user finishes adding the new slide - i.e. if successful call [self.tableview reloadData] from that method instead of in viewWillAppear.

UITableView not scrolling smoothly...(iPhone SDK) ..!

UITableView not scrolling smoothly...(iPhone SDK) ..!!
I have implemented UITableView DataSource and Delegate methods in an individual separate classes.(one for delegate and one for datasource) in main program i write only:
//assume that all objects are allocated
ObjTableView.dataSource=ObjDataSource;
ObjTableView.delegate = ObjDelegate;
[self.view addSubView: ObjTableView];
when i run this code , UITable view appears but when i try to scroll it, it doesn't scroll smoothly.
I have also checked that UITableViewCell doesn't redraw once the cell is initialized.
can any one tell me why this happens ? How can i solve this problem ??
From comments:
ListDataSource *ObjListDataSource = [[ListDataSource alloc]initWithArray:[[sender object] valueForKey:#"List"]];
ListDelegate *ObjListDelegate = [[ListDelegate alloc]initWithArray:[[sender object] valueForKey:#"List"]];
tblList = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320, 460)];
tblList.dataSource = ObjListDataSource; tblList.delegate = ObjListDelegate;
[self.view addSubview:tblList]; [tblShopList release];
More from comments:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [NSString stringWithFormat:#"%i",indexPath.row];
UITableViewCell *cell = (UITableViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,320,100) reuseIdentifier:CellIdentifier] autorelease];
//custom cell code
}
return cell;
}
More Information:
I have used NSNotification which notifies to current class when parsing is complete, after receiving notification , current class method calls DataSource, Delegate methods (which is defined in a separate class file).
So UItableViewCell customization (which is in ListDataSource) and table view(in current class) both are in different classes.
A problem is
NSString *CellIdentifier = [NSString stringWithFormat:#"%i",indexPath.row];
The id needs to be the same for all cells of the same class, otherwise you never reuse them. As you can see in most examples, it is indeed a constant in most (all?) cases.
Little explaination on the reuseIdentifier: every time a cell gets out of screen, you can reuse it instead of creating a new one. To reuse it, you need a cell in queue with the same identifier as the one you pass to dequeueReusableCellWithIdentifier. The way you did, the cells are never reused, because each id is unique (they may or may not be reused in case a row reappears on screen, depending on queue size, which is not configurable AFAIK). This is why personalization of the cell should happen OUTSIDE the "cell == nil" block. Long story short, you are using the reuseIdentifier not as intendend.
I think Michele is correct, but I would also add that it looks like you are doing your cell customization where the cell gets created. What you should be doing is something more like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = (UITableViewCell)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,320,100) reuseIdentifier:CellIdentifier] autorelease];
//custom REUSABLE cell code here, e.g. text color, etc.
}
NSString *cellText = [dataArray objectAtIndex:indexPath.row]; //assuming you have a simple array for your data
cell.textLabel.text = cellText;
return cell;
}
I would also add that I'm not sure why you are able to run the app with the code you have here, since UITableViewCell cell = ... is an invalid initializer. It should be UITableViewCell *cell = ....
It would be helpful to see how you are customizing your cell, since without that it's hard to see what's happening.

UITextField inside of UITableViewCell will not activate on iPad but works on iPhone

I have a UITextField inside a UITableViewCell. It will not activate on the iPad (but it works fine on the iPhone) no matter what I try. Tapping on it and telling it to become the firstResponder both fail. The odd thing is that if I take the exact same code and move it to another view controller in my app it executes just fine. This makes it seem as if there is likely a problem in the parent UITableViewController but I can't find anything obvious. I'm hoping that someone out there has experienced a similar problem and can point me in the right direction.
Below is the sample code that works fine when I move it to a new project or put it in a new view controller launched immediately by my app delegate:
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (indexPath.row == 0) {
UITextField *nameText = [[UITextField alloc] initWithFrame:CGRectMake(5, 5, cell.contentView.frame.size.width, cell.contentView.frame.size.height)];
nameText.delegate = self;
nameText.backgroundColor = [UIColor redColor];
[cell.contentView addSubview:nameText];
[nameText becomeFirstResponder];
[nameText release];
}
// Configure the cell...
return cell;
}
Help!
As is typical for me if I just ask the question I find the answer a few moments later. It turns out I did have a view several steps before that had asked for the first responder but not resigned it. Live and learn!