0

step by step I am advancing creating my first iOS app. Now I am experiencing a strange behaviour on a table view controller which I am not able to solve and I have been searching for the reason for hours. THis is the scenario:

  1. Simple iOS app using core data.
  2. Table view controller to show one core data entity objects.
  3. One view controller (AddViewController) to enter several attributes values.
  4. One view controller (EditViewController) to update the object values (after row selection on the table view controller.

To make the question clear enough, I will only take into account three of the attributes, 'thingName' , 'urgent' and 'color', all string attributes. Every row shows a string (thingName), an image as icon for the color attribute and another image as icon for the urgent attribute. The app process begin with a blank table, after pressing the Add button, the app shows the AddViewController view, that is a view with a text field (thingName), a switch to mark the object as urgent/not urgent and a group of colored buttons to assign a color dependency to the object. After introducing the thingName, selecting the object as urgent or not urgent, and selecting one of the colour buttons, the user taps on the save button and then to the back button to go back to the table view controller. Everything works as expected. A new row appears containing the thingName text as cell.text, the icon representing that the object was marked as urgent and a color pencil from the color selected by the user. Then, if the user wants to change the thingName text / urgent or not urgent / colour, selecting the object row, the app shows the editViewController. If the user changes the text and after saving, the updated text is also shown on the tableview, which means that the app has stored the changes. If the user changes the urgent state, from not urgent to urgent, after saving and going back to the table view, the urgent icon appears as expected, but after changing from urgent to not urgent, saving and going back to the table view, the urgent icon that shouldn't appear, does appear. To check the issue I have included a text field (urgentTextField) on the editviewcontroller to show the content of the urgent attribute, and it changes fine in response from the switch state. That means, if the user sets the switch to no urgent, the urgentTextField shows 'Not urgent', if the user sets the switch to urgent, the urgentTextField shows 'Urgent'. Sample case:

thingName = @"test";
urgentTextField.text=@"Not urgent";

In this case, the row shows the expected text 'test'. but the icon is not responding as expected, then the urgent icon is shown.... To make it easier, this is the code:

RootViewController (table view controller):

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];        

    NSString *colorValue = [[managedObject valueForKey:@"color"] description];
    NSString *isUrgent = [[managedObject valueForKey:@"urgent"]description];

   [[cell textLabel] setText:[[managedObject valueForKey:@"thingName"] description]];
  NSString *myString = [NSString stringWithFormat:@"%@",[[managedObject valueForKey:@"todoYear"] description]];

    //color pencil

    if ([hasColorValue  isEqual:@"Si color"]){
        UIButton *colorButton = [[UIButton alloc]initWithFrame:CGRectMake(308, 5, 10, 40)];
        [colorButton setImage:[UIImage imageNamed:colorValue]forState:UIControlStateNormal];
        [cell addSubview:colorButton];
    }

    //urgent
    if ([isUrgent isEqual:@"Urgent"]){
        UIButton *urgentButton = [[UIButton alloc]initWithFrame:CGRectMake(71, 27, 18, 18)];
        [urgentButton setImage:[UIImage imageNamed:@"urgent-3"]forState:UIControlStateNormal];
        [cell addSubview:urgentButton];
    }

  ../..

And this is the code for EditViewController:

- (IBAction)SaveButtonAction:(id)sender {

    AppDelegate* appDelegate = [AppDelegate sharedAppDelegate];
    NSManagedObjectContext* context = appDelegate.managedObjectContext;

    [selectedObject setValue:ToDoTextField.text forKey:@"thingName"];
    NSString *valorUrgent = urgentTextField.text;
    [selectedObject setValue:valorUrgent forKey:@"urgent"];

    NSError *error;
    if(! [context save:&error])
    {
        NSLog(@"Whoopw,couldn't save:%@", [error localizedDescription]);
    }
}

- (void)viewDidLoad
{
    colorImagen.image = [UIImage imageNamed:nil];
    [ToDoTextField becomeFirstResponder];

    //recogiendo datos de selectedobject;
    ToDoTextField.text = [[selectedObject valueForKey:@"thingName"]description];
    colorTextField.text = [[selectedObject valueForKey:@"color"]description];
    NSString *imageName = colorTextField.text;
    colorImagen.image = [UIImage imageNamed:imageName];
    NSString *urgentValue = [[selectedObject valueForKey:@"urgent"]description];
    urgentTextField.text = urgentValue;

    if ([urgentValue isEqual:@"Urgent"]){
        [urgentSwitch setOn:YES animated:YES];
        urgentImage.image=[UIImage imageNamed:@"urgent-3"];
    }
    if ([urgentValue isEqual:@"Not urgent"]){
        [urgentSwitch setOn:NO animated:YES];
        urgentImage.image=[UIImage imageNamed:nil];
    }

    [ToDoTextField addTarget:self action:@selector(textFieldDidChange) forControlEvents:UIControlEventEditingChanged];

    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

Please, tell me if you need further information or code to detect where is the problem that I am not able to find. Thank you

Shaik Riyaz
  • 11,204
  • 7
  • 53
  • 70
mvasco
  • 4,965
  • 7
  • 59
  • 120

2 Answers2

3

Your problem appears to be in the configureCell: method. You are not taking cell reuse into account. The cell you are configuring could have need used before and could have had an urgent status previously.

Your code only deals with the situation where the cell is urgent, in which case it adds a subview. There are two problems with this approach:

  1. A reused cell will have the subview added every time - so there could be many urgent views on top of each other. The cell should only ever add this once and keep it in a property
  2. Code must be added to configure the cell when it is not urgent (usually, an else after the if). This would hide the urgent icon.
jrturton
  • 118,105
  • 32
  • 252
  • 268
  • Thank you for your answer, I understand what you mean and I have implemented point #2 from your answer, but this point alone doesn't solve my problem. I need your help to implement point #1. Thank you again. – mvasco Dec 26 '13 at 16:44
  • I think I will ask another question focused on the reused cell issue. Thank you. – mvasco Dec 26 '13 at 18:59
0

The first issue with code I noticed is you must add you code after

[super viewDidLoad];
// Do any additional setup after loading the view from its nib.

not before it. It will guarantee that your view is, at least, loaded.

Second, make from all your string literals const string like this and use it everywhere

static NSString * const kUrgentState = @"Urgent";

And one more common hint: add NSLog(...); or test the value of variable in debug to localise the problem, cause right now it's really to much code, but not still not enough to find a problem. Find the moment when values of variable goes wrong and then fix your question

Ossir
  • 3,109
  • 1
  • 34
  • 52