在不使用tag属性的情况下在表视图中处理多个UISwitch控件

时间:2010-04-01 10:34:34

标签: objective-c iphone cocoa-touch uiswitch

我有一个包含多个UISwitch控件的表视图控制器。我将委托设置为表视图控制器,对所有交换机执行相同的操作。我需要能够确定哪个开关已更改,因此我创建了一个包含每个开关名称的字符串数组。数组中的索引将放在每个UISwitch的tag属性中。

但是,我已经准备好将tag属性用于其他东西,即使用viewWithTag在cellForRowAtIndexPath中的单元格中找到正确的控件! (我需要在每个单元格中设置几件事。)

那么,我在这里思考的是正确的思路吗?我觉得我对如何确切地知道哪个UISwitch改变了它的价值非常有限,所以我可以用它做一些有用的事情。

4 个答案:

答案 0 :(得分:5)

我通过子类化UISwitch修复了这个问题:

@interface NamedUISwitch : UISwitch {
NSString *name;

}

看起来很优雅(不需要索引数组),标签属性可以随意做任何事情。

我读到你必须小心使用Objective-C中的子类化,但是......

答案 1 :(得分:1)

我编写了一个UISwitch子类,其中包含基于块的处理器,用于更改值控制事件,这有助于在尝试跟踪哪个交换机的值发生更改时有所帮助。理想情况下,我们可以使用组合而不是子类化来做类似的事情,但这很适合我的需要。

https://gist.github.com/3958325

你可以像这样使用它:

ZUISwitch *mySwitch = [ZUISwitch alloc] init];

[mySwitch onValueChange:^(UISwitch *uiSwitch) {
        if (uiSwitch.on) {
            // do something
        } else {
            // do something else
        }
    }];

您也可以在XIB文件中使用它,方法是将开关拖到视图上,然后将其类更改为ZUISwitch

答案 2 :(得分:0)

你的方法很接近。我在类似情况下所做的是创建单独的UITableViewCell子类,将UISwitch的标记设置为索引路径的index.row,并且仅在表视图的特定部分中使用该UITableViewCell子类。这允许您使用单元格的标记来唯一地确定具有该事件的单元格而不维护单独的索引列表(因为它听起来像您正在做的那样)。

因为单元格类型是唯一的,所以您可以通过在UITableViewCell子类上创建方法/属性来轻松访问单元格的其他元素。

例如:

@interface TableViewToggleCell : UITableViewCell {
    IBOutlet UILabel *toggleNameLabel;
    IBOutlet UILabel *detailedTextLabel;
    IBOutlet UISwitch *toggle;
    NSNumber *value;
    id owner;
}

@property (nonatomic, retain) UILabel *toggleNameLabel;
@property (nonatomic, retain) UILabel *detailedTextLabel;
@property (nonatomic, retain) UISwitch *toggle;
@property (nonatomic, retain) id owner;

-(void) setLable:(NSString*)aString;
-(void) setValue:(NSNumber*)aNum;
-(NSNumber*)value;
-(void) setTagOnToggle:(NSInteger)aTag;

-(IBAction)toggleValue:(id)sender;

@end

在:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // ... prior iniitalization code for creating cell is assumed
toggleCell.owner = self;
[toggleCell setLable:@"some string value"];
[toggleCell setTagOnToggle:indexPath.row];
toggleCell.owner = self;
return toggleCell;
   //...  handle cell set up for other cell types as needed
}

所有者是单元格的委托,然后可用于在控制器中启动操作。确保将UISwitch连接到toggleValue Action,以便在UISwitch更改状态时可以在委托中启动操作:

-(IBAction)toggleValue:(id)sender;
{
    BOOL oldValue = [value boolValue];
    [value release];
    value = [[NSNumber numberWithBool:!oldValue] retain];
    [owner performSelector:@selector(someAction:) withObject:toggle];
}

通过使用方法调用传递UISwitch,您可以访问该单元的索引路径。您还可以通过显式地使用ivar来存储单元格的NSIndexPath,然后通过方法调用传递整个单元格来绕过tag属性的使用。

答案 3 :(得分:0)

我意识到我已经迟到了三年,但我已经开发出了一种没有子类化的解决方案,我认为这是更好的(而且更简单)。我正在使用与Thaurin描述的场景完全相同的场景。

- (void)toggleSwitch:(id) sender
{
    // declare the switch by its type based on the sender element
    UISwitch *switchIsPressed = (UISwitch *)sender;
    // get the indexPath of the cell containing the switch
    NSIndexPath *indexPath = [self indexPathForCellContainingView:switchIsPressed];
    // look up the value of the item that is referenced by the switch - this
    // is from my datasource for the table view
    NSString *elementId = [dataSourceArray objectAtIndex:indexPath.row];
}

然后你要声明上面显示的方法indexPathForCellContainingView。这是一个看似不必要的方法,因为它乍一看似乎你所要做的就是确定交换机的超级视图,但ios7和早期版本的超级视图之间存在差异,因此这将处理所有:

- (NSIndexPath *)indexPathForCellContainingView:(UIView *)view {
    while (view != nil) {
        if ([view isKindOfClass:[UITableViewCell class]]) {
            return [self.myTableView indexPathForCell:(UITableViewCell *)view];
        } else {
            view = [view superview];
        }
    }   
    return nil;
}