2

Updated up my question

I've got a settings page where I am showing the setting name on the left, and what the current setting is on the right (UITableViewCellStyleValue1). When you tap a setting's cell, you get an action sheet that lets you select "View All", "Yes", "No". My goal is to put the value they select into the right side of the cell so that they can see a change was made.

Action Sheet Event

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex == 0) {
        thisVal = @"Show All";
        NSLog(@"Button 0");
    } else if (buttonIndex == 1) {
        thisVal = @"Yes";
        NSLog(@"Button 1");
    } else if (buttonIndex == 2) {
        thisVal = @"No";
        NSLog(@"Button 2");
    } else if (buttonIndex == 3) {
        NSLog(@"Button 3");
    }

    [self saveSettings:thisKey :thisVal];

    NSLog(@"Before: %@",[table2settings objectAtIndex:(NSUInteger)thisRow]);

    if (thisSection == 0){
        [table1settings replaceObjectAtIndex:(NSUInteger)thisRow withObject:thisVal];
    }else{
        [table2settings replaceObjectAtIndex:(NSUInteger)thisRow withObject:thisVal];
    }

    NSLog(@"After: %@",[table2settings objectAtIndex:(NSUInteger)thisRow]);

    [self.tblView reloadData];
}

Because of the Before and After NSlog's, I can see that the actual array is being updated. But the tblView does not reload. the data.

cellForRowAtIndexPath

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier;
    if (indexPath.row == 0 && indexPath.section == 0){
        CellIdentifier = @"CellWithSwitch";
    }else{
        CellIdentifier = @"PlainCell";
    }


    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
    }

    if (indexPath.section == 0){
        [[cell textLabel] setText:[table1labels objectAtIndex:indexPath.row]];
        if (indexPath.row == 0 && indexPath.section == 0){
            BOOL switchOn;
            if ([[table1settings objectAtIndex:indexPath.row] isEqualToString: @"On"]){
                switchOn = YES;
            }else{
                switchOn = NO;
            }

            switchview = [[UISwitch alloc] initWithFrame:CGRectZero];
            [switchview setOn:switchOn animated:YES];
            [switchview addTarget:self action:@selector(updateCurrentLocation) forControlEvents:UIControlEventValueChanged];
            cell.accessoryView = switchview;
        }else{

            if (![[table1settings objectAtIndex:indexPath.row] isEqualToString: @""]){
                [[cell detailTextLabel] setText:[table1settings objectAtIndex:indexPath.row]];
            }else{
                [[cell detailTextLabel] setText:@""];
            }
        }
    }else{
        if (![[table2settings objectAtIndex:indexPath.row] isEqualToString: @""]){
            [[cell detailTextLabel] setText:[table2settings objectAtIndex:indexPath.row]];
        }else{
            [[cell detailTextLabel] setText:@""];
        }
        [[cell textLabel] setText:[table2labels objectAtIndex:indexPath.row]];

    }

    return cell;
}

More information

Here's my .h file's @interface:

NSMutableArray *table1settings;
NSMutableArray *table2settings;

And under that:

@property (nonatomic, retain) NSMutableArray *table1labels;
@property (nonatomic, retain) NSMutableArray *table2labels;

And my .m file:

@synthesize table1settings;
@synthesize table2settings;

updateCurrentLocation

- (void)updateCurrentLocation {
    switchview.on ? [self saveSettings:@"useLocation" :@"On"] : [self saveSettings:@"useLocation" :@"Off"];
    NSLog(@"%@", [self loadSettings:@"useLocation"]);
}

More again

@interface DOR_FiltersViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UIActionSheetDelegate>
UITableView *tblView;
@property (nonatomic, retain) UITableView *tblView;
@synthesize tblView;

Also, for @implementation DOR_FiltersViewController, I am getting a warning saying "Incomplete implementation". I have no clue what that generic statement could possibly mean. Tried looking it up, and it almost seems like it could mean anything.

The Fix

First, I found that I did not have tblView connected to my table view. -.- I had to right-click the table view and drag it to my .h file and link it to tblView. I thought I had already done this. I feel very foolish now. Then, for the @interface, I had to use __weak IBOutlet UITableView *tblView;, and under that @property (weak, nonatomic) IBOutlet UITableView *tblView; Then it all worked.

James
  • 3,765
  • 4
  • 48
  • 79
  • 4
    Reloading the table will have no effect unless you have updated the data model - the code you'd need to include would be your cellForRowAtIndexPath method and whatever is run when the action sheet is called / dismissed – jrturton Mar 28 '12 at 12:32
  • Please post your actionSheet callback and the cellForRowAtIndexPath callback. – Mat Mar 28 '12 at 12:33
  • What do you mean by you're not using `cellForRowAtIndexPath:` anymore? – Rok Jarc Mar 28 '12 at 12:52
  • 1
    You don't have to (nor shouldn't) call `cellForRowAtIndexPath:`, but it has to be implemented for `UITableView` to work. I understood that you have deleted this method from code, that's why i was asking. – Rok Jarc Mar 28 '12 at 13:05
  • 1
    @rokjarc Oh, that's a typo (copy/paste). I'm not using `reloadRowsAtIndexPaths` anymore. – James Mar 28 '12 at 13:11
  • A, ok. :) Then you should follow jrturton's advice - you have to modify the model (the place where you hold your data/settings and then call reloadData. – Rok Jarc Mar 28 '12 at 13:13
  • @rokjarc Yeah, that's why I implemented the if/else statement above to change the array that the `cellForRowAtIndexPath` uses to fill the table. But I am now getting that bad access error in the if statement. – James Mar 28 '12 at 13:16
  • incomplete implementation warning means you didn't implement all or the required methods of your adopted protocols (`UITableViewDataSource, UITableViewDelegate, UIActionSheetDelegate`) or that you declared one method in .h and forgot to implement it in .m file (or the method is implemented but there's a type in its name...) – Rok Jarc Mar 28 '12 at 15:45
  • @rokjarc Yeah, I've checked that all the methods I have in my .h are in the .m, and the return type is specified. Do I need to include the input types as well? I only have it like `- (return type) method name;`. Should I change it to `- (return type) method name: (input type *) input variable;`? – James Mar 28 '12 at 15:58
  • Yes, i usually just copy the whole line with method names and params from .m to .h. For example: if there's `- (void)updateCurrentLocation:(id)sender {...}` in a .m file i copy `- (void)updateCurrentLocation:(id)sender;` to .h file. – Rok Jarc Mar 28 '12 at 16:04

1 Answers1

2

Two things: table1settings and table2settings should be NSMutableArray though according to the error you get this isn't the problem.

It looks like thisVal is an iVar of your class. You should allocate it inside clickedButtonAtIndex:

Try this:

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {

    NSString *thisVal; //this line was added

    if (buttonIndex == 0) {
        thisVal = @"Show All";
        NSLog(@"Button 0");
    } else if (buttonIndex == 1) {
        thisVal = @"Yes";
        NSLog(@"Button 1");
    } else if (buttonIndex == 2) {
        thisVal = @"No";
        NSLog(@"Button 2");
    } else if (buttonIndex == 3) {
        NSLog(@"Button 3");
    }

    [self saveSettings:thisKey :thisVal];

    if (thisSection == 0){
        NSLog(@"thisRow is %d and table1settings has %d elements", thisRow, [table1settings count]);
        [table1settings replaceObjectAtIndex:(NSUInteger)thisRow withObject:thisVal];
    }else{
        NSLog(@"thisRow is %d and table2settings has %d elements", thisRow, [table2settings count]);
        [table2settings replaceObjectAtIndex:(NSUInteger)thisRow withObject:thisVal];
    }
    [self.tblView reloadData];
}

And of course remove the other implementation of thisVal (probably in the @interface part).

Also note that replaceObjectAtIndex: has the following structure:

- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject

There should be simple NSUinteger for index.

EDIT:

If calling [self.tblView reloadData]; doesn't initiate any cellForRowAtIndexPath: calls then self.tblView is not referenced properly.

EDIT 2:

Make sure that the class where - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath lies adopts UITableViewDataSource protocol.

You do this in .h file, for example:

@interface YourClass:UIViewController <UITableViewDataSource>

And you should let the table know who her dataSource is. In the code, wher you set

self.tblView = thatTable;

add

self.tblView.dataSource = self;

And if you're using any of UITableViewDelegate methods you have to throw that into the mix:

@interface YourClass:UIViewController <UITableViewDataSource,UITableViewDelegate>

and

self.tblView.delegate = self;
Rok Jarc
  • 18,765
  • 9
  • 69
  • 124
  • @James: you probably have `thisRow` declared as `(NSUInteger *)`. It should be declared as simple `NSUInteger` and treated as such (in all parts of the code where it's used). Also: are you sure your array is populated before calling `replaceOBjectAtIndex:`. If index is bigger then number of objects in array-1 you'll get an error. I added two NSLog statements in my answer. Try it out and post the results. – Rok Jarc Mar 28 '12 at 14:58
  • @James: no problem. In that case either `self.tblView` is not correctly referenced (ie. it's not pointing to the `tblView`) or self is not a `tableViewDelegate` or `tableViewDataSource`. Are you creating `tableView` programatically or with IB? Do you set `tblView.dataSource` and `tblView.delegate`? Do you have `` in your .h file? – Rok Jarc Mar 28 '12 at 15:10
  • Added all of the info for your last comment at the bottom of my question post. I do not have `tblView.dataSource` or `tblView.delegate` anywhere. – James Mar 28 '12 at 15:16
  • Just updated my answer (and deleted some comments that are not neccessery anymore). – Rok Jarc Mar 28 '12 at 15:31
  • Also: you should remove `UITableView *tblView;` from your interface. That way you'll make sure you're not mixing iVar and property. If you get any compile errors after removing that line make sure that everywhere wher you use tblView you type `self.tblView` – Rok Jarc Mar 28 '12 at 15:34
  • This wasn't too far off. Because of the way I created everything, I had to do this a different way. But I'll mark this as the answer and update my question with my new code. – James Mar 28 '12 at 15:41
  • 1
    Yup, and I very much appreciate the help. – James Mar 28 '12 at 15:56
  • 1
    RE: Edit1. Thank you! In my case, was caused by a Storyboard TableViewController that did not have its "view" property connected to the "tableView" object on screen. – ObjectiveTC Jul 02 '14 at 09:47