views:

44

answers:

2

Hi All,

Caveat: I have looked for the answer to my question and several come close, but I'm still missing something. Here is the scenario:

I want a way to create UITableViewCells that contain UISwitches dynamically at run time, based on the data in a table (which I can do). The problem becomes connecting the switches such that I can get their value when that view is changed (navigated away, closed, etc). I have tried to use the events UIControlEventValueChanged to be notified, but have failed to specify it correctly, because it dumps when that switch is tapped. Also, there doesn't seem to be any way to uniquely identify the switch so that if all the events are handled by a single routine (ideal), I can't tell them apart.

So...

If I have a UITableView:

@interface RootViewController : UITableViewController 
{
    UISwitch * autoLockSwitch;
}

@property (nonatomic, retain) UISwitch * autoLockSwitch;
-(void) switchFlipState: (id) sender;
@end

// the .m file:

@implementation RootViewController
// ...


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString * CellIdentifier = @"Cell";
    int row          = 0;
    NSString * label = nil;
    TableCellDef_t  * cell_def = nil;

    row = indexPath.row;
    cell_def = &mainMenuTableCellsDef[ row ];

    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
    label = (NSString *) mainMenuTableCellsDef[indexPath.row].text;
    [cell.textLabel setText:(NSString *) mainMenuItemStrings[ indexPath.row ]];
    if (cell_def->isSpecial)  // call special func/method to add switch et al to cell.
    {
        (*cell_def->isSpecial)(cell );  // add switch, button, etc.
    }
    else
    {
        [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
    }
}


and this is the 'special' function:

-(void) autoLockSpecialItem :(UITableViewCell *) cell
{
    autoLockSwitch = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
    [autoLockSwitch addTarget:self action:@selector(switchFlipState:) forControlEvents:UIControlEventValueChanged ];
    [cell addSubview:autoLockSwitch];
    cell.accessoryView = autoLockSwitch;
}

and finally:

-(void) switchFlipState: (id) sender
{
    NSLog(@"FLIPPED");
}

==============================================================

Questions:

  1. Why would it crash (bad selector) when the switch was tapped? I believe that my code follows all the example code that I have seen, but obviously something is wrong.

  2. I cannot put a instance method into a table as a function pointer; and it doesn't seem to like a class method either. If I make it a 'C/C++' function, how do I get access to the class/instance member variables? That is, if I want to put a call to autoLockSpecialItem into a static table (or reasonable facsimile) such that I can get autoLockSwitch member variable? If I make it a class method and the autoLockSwitch var a static, will that be valid?

  3. More simply: how do I connect the UIControlEventValueChanged to my view (I have tried and failed) and can I differentiate at runtime within the event handler which switch has changed?

  4. Is there a better way? I cannot believe that I am the first person to have to solve this type of problem.

Apologies for the length, appreciation for attention and grateful for any and all help.

:bp:

A: 

Don't know about why your method isn't connected, but a simple way to "differentiate at runtime within the event handler which switch has changed" is to take the (id)sender given to your event handler, walk your tableview, and compare the sender to any switches, if present, in each table item. If that's too slow, a hash table connecting senders to table cells, or something like that, is a possible optimization.

If you want to use C function pointers, you need to pass the object to the function to use it to call the object's property accessor methods within the function. (Or you could assign the object to a global variable if it's clearly a singleton, but that's a very politically incorrect answer.)

hotpaw2
A: 

First, and easy way to define your different switches would be defining their tag based on the row number. When one of the switches is tapped you can access sender.tag to get the row number this way.

Also, you should probably be adding the switch the the cells content view, not the actual cell, [cell.contentView addSubview:autoLockSwitch]. Also the frame does need to be set (note CGRectZero, cocoa will ignore the width and height but uses the x,y coords to define where you want the switch in the cell.

thelaws
Thank you. I thought that the .tag was deprecated in iOS4 -- is it not? Why should the switch be connected to the content view instead of the cell? Would the switch still scroll with the cell if I did that?
Billy Pilgrim
No, tag isn't decorated, check out the `UIView` class reference for the tag property. Also, check out the doc for `UITableViewCell` contentView. The contentView is mean't to be the superview to all components of the cell. And Yes, the switch will still scroll.
thelaws