views:

363

answers:

3

I'm building an iphone app that uses table views contained within UIViewControllers pushed onto a UINavigation controller (very similar to the Contacts app). When you touch a particular table cell it pushes a new view controller onto the navigation controller to allow you to select a value from a table view list. When you select and touch "save" it pops that view off the stack and moves you back to the first view, where the original table view should show the value you selected.

The problem is that I'm storing the selected value in a @property located in the first view controller, and it doesn't seem to be getting the value that is selected. This is happening in the "setDiff" method. I can log it out and it seems to have been set, but the it's not set when the view renders after the property has been changed.

This is the code for the first view controller (where the selected value from the second view controller will be displayed after it is selected).

/**
 *
 * ManageWorkoutViewController
 *
 **/
@class ManageWODiffController;

@interface ManageWorkoutViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {

    IBOutlet ManageWODiffController *workoutDifficultyController;
    IBOutlet UITableView *woTableView;
    IBOutlet UITableViewCell *workoutCommentsCell;
    IBOutlet UITableViewCell *workoutDifficultyCell;
    IBOutlet UITableViewCell *workoutDateCell;
    NSString *workoutDifficulty;
    NSString *workoutDate;
}

@property (nonatomic, retain) UITableView *woTableView;
@property (nonatomic, retain) NSString *workoutDifficulty;
@property (nonatomic, retain) NSString *workoutDate;

-(void)setupWorkoutAddEdit;
-(void)setDiff:(NSString *)value;

@end



#import "ManageWorkoutViewController.h"
@implementation ManageWorkoutViewController

@synthesize woTableView;
@synthesize workoutDifficulty;
@synthesize workoutDate;


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell;

    if (indexPath.row == 0) {

        //workout comments
        cell = [tableView dequeueReusableCellWithIdentifier:@"workoutCommentsCell"];
        if (nil == cell) { 
            cell = workoutCommentsCell;
            cell.selectionStyle = UITableViewCellStyleValue1;
        }

    }else if (indexPath.row == 1) {

        //difficulty
        cell = [tableView dequeueReusableCellWithIdentifier:@"workoutDifficultyCell"];
        if (nil == cell) { 
            cell = workoutDifficultyCell;
            cell.selectionStyle = UITableViewCellStyleValue1;
            cell.textLabel.text = self.workoutDifficulty;
        }

    }else if (indexPath.row == 2) {

        //workoutDate
        cell = [tableView dequeueReusableCellWithIdentifier:@"workoutDateCell"];
        if (nil == cell) { 
            cell = workoutDateCell;
            cell.selectionStyle = UITableViewCellStyleValue1;
            cell.textLabel.text = self.workoutDate;
        }

    }//end if-else


    return cell;

}//end cellForRowAtIndexPath


- (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {

    return 3;

}//end numberOfRowsInSection


-(void)setDiff:(NSString *)value{

    self.workoutDifficulty = value;
    [woTableView reloadData];
    NSLog(@"setter: workoutDifficulty set as: %@", self.workoutDifficulty);

}//end setDiff


-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


    switch (indexPath.row) {

        case 0:
            //do nothing no nav-view here
            break;

        //DIFFICULTY
        case 1:
            workoutDifficultyController.title = @"Workout Difficulty";
            workoutDifficultyController.originalDifficulty = self.workoutDifficulty;//set the selected difficulty string
            [tableView deselectRowAtIndexPath:indexPath animated:YES];
            [(UINavigationController *)self.parentViewController pushViewController:workoutDifficultyController 
                                                                           animated:YES];
            break;

        case 2:
            workoutDateController.title = @"Workout Date";
            [tableView deselectRowAtIndexPath:indexPath animated:YES];
            [(UINavigationController *)self.parentViewController pushViewController:workoutDateController 
                                                                           animated:YES];
            break;


        default:
            break;

    }//end switch



}//end didSelectRowAtIndexPath


- (void)viewWillAppear:(BOOL)animated {

    //setup the UI to add / edit the workout
    [self setupWorkoutAddEdit];

    [super viewWillAppear:animated];

}//end viewWillAppear


-(void)setupWorkoutAddEdit{

    //load the difficulty 
    if (nil == self.workoutDifficulty) {


        switch ([[workout retrieveValueForKey:@"workoutDifficultyId"] intValue]) {
            case 0:
                self.workoutDifficulty = @"Easy";
                break;
            case 1:
                self.workoutDifficulty = @"Medium";
                break;
            case 2: 
                self.workoutDifficulty = @"Hard";
                break;
            default:
                break;
        }

    }//end if nil


    NSLog(@"workoutDifficulty is: %@", self.workoutDifficulty);

}//end setupWorkoutAddEdit

@end

Here is the code for the ManageWODiffController (where a value is selected from a table view and saved).

/**
 *
 * ManageWODiffController
 *
 **/

@class ManageWorkoutViewController;

@interface ManageWODiffController : UIViewController <UITableViewDelegate> {
    IBOutlet UITableView *tableView;
    IBOutlet UITableViewCell *checkCell;
    NSString *selectedDifficulty;
    NSString *originalDifficulty;
    IBOutlet ManageWorkoutViewController *manageWorkoutController;
}

@property (nonatomic, retain) UITableView *tableView;
@property (nonatomic, retain) NSString *selectedDifficulty;
@property (nonatomic, retain) NSString *originalDifficulty;

-(IBAction)cancelDifficulty:(id)sender;
-(IBAction)saveDifficulty:(id)sender;

@end



#import "ManageWODiffController.h"
#import "ManageWorkoutViewController.h"


@implementation ManageWODiffController

@synthesize tableView;
@synthesize selectedDifficulty;
@synthesize originalDifficulty;


-(IBAction)saveDifficulty:(id)sender {

    NSLog(@"[ManageWODiffController.saveDifficulty] returning: %@", self.selectedDifficulty);

    [manageWorkoutController setDiff: self.selectedDifficulty];

    [(UINavigationController *)self.parentViewController popViewControllerAnimated:YES];

}//end saveDifficulty


-(IBAction)cancelDifficulty:(id)sender { /*...*/ }


- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath { /*...*/ }


- (NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section { /*...*/ }


 @end
+2  A: 

You should try to add [self.tableView reloadData] to your viewWillAppear (between the two other statements) in the first controller.

Kai
I tried this and got a crash with the error: -[CFString isEqualToString:]: message sent to deallocated instance 0x3b78110. (Note NSZombieEnabled is turned on). Not sure why since isEqualToString is only used in the cellForRowAtIndexPath of the second view controller (nowhere in the first)
bwizzy
seems as if "self.tableView" references the tableView of the second view controller. Can't tell from the code you pasted why that happened...
Kai
Logging the value from viewWillAppear after the setupWorkoutAddEdit method shows the value hasn't changed.
bwizzy
woTableView is the TableView in the first controller, and tableView is the TableView in the second controller. The crash is caused by [woTableView reloadData]; in the viewWillAppear method of the first controller.
bwizzy
Is the log statement in saveDifficulty shown, i.e. get the method invoked when you expect it to be? If so and if the value does not change, the managerWorkoutController is either nil or another instance.
Kai
Looks like it is possible the manageWorkoutController is a different instance. I added a log of the manageWorkoutController in saveDifficulty (of the second controller) and of self in the first controller. I got two different memory locations in the log: <ManageWorkoutViewController: 0x3b53700><ManageWorkoutViewController: 0x397b9a0>. I made the association from the second controller to the first in IB, how do I correct it, if this is indeed the problem?
bwizzy
Seems to make sense now ... My own approach to a similar problem is slightly different from yours by using a context object which is handed over from one controller to the other, collecting the data. I will make a sketch in a new answer
Kai
A: 

How about this...

...
//difficulty
cell = [tableView dequeueReusableCellWithIdentifier:@"workoutDifficultyCell"];
if (nil == cell) { 
    cell = workoutDifficultyCell;
    cell.selectionStyle = UITableViewCellStyleValue1;
}
cell.textLabel.text = self.workoutDifficulty;
...
wkw
The value of self.workoutDifficulty still isn't updated. I think it is not related to the table view, because if I log the value in viewWillAppear it is unchanged.
bwizzy
Also, selectionStyle isn't the same thing as the cell's style. The cell's style cannot be changed after the cell is initialized. Selection style defines whether the cell displays a blue, gray or no change when the cell becomes selected.
Jason Coco
A: 

Approach with context object: In your 1st controller, the ManageWorkoutViewController, invent an context object

@property (nonatomic, retain) NSMutableDictonary *workout;

In the table cell where the difficulty is shown it should be picked from

[workout objectForKey:@"Difficulty"];

Do the same in the second controller (ManageWODiffController ).

Then in the first one you go like this

//DIFFICULTY
    case 1:
       ManageWODiffController *diffController = [[ManageWODiffController alloc]        initWithNibName:@"ManageWODiffController" bundle:[NSBundle mainBundle]];
       diffController.workout = workout;
       [[self navigationController] setNavigationBarHidden:NO animated:NO]; 
       [self.navigationController pushViewController:diffController animated:YES];
       [diffController release];
       diffController = nil; 
          break;

In the second controller it should be like

-(IBAction)saveDifficulty:(id)sender
{
    [workout setObject: selectDifficulty forKey:@"Difficulty"];
}

Then after putting the difficulty in the workout context pop the second controller.

[[self navigationController] popViewControllerAnimated:YES];

If you do so a

[self.tableView reloadData];

in the first controller should be enough to make things work

Kai