Objective c 在表视图中处理多个UISwitch控件而不使用标记属性

Objective c 在表视图中处理多个UISwitch控件而不使用标记属性,objective-c,iphone,cocoa-touch,uiswitch,Objective C,Iphone,Cocoa Touch,Uiswitch,我有一个带有多个UISwitch控件的表视图控制器。我将委托设置为表视图控制器,并对所有开关执行相同的操作。我需要能够确定更改了什么开关,所以我创建了一个字符串数组,其中包含每个开关的名称。数组中的索引将放在每个UISwitch的tag属性中 但是,我已经准备好使用tag属性进行其他操作,即使用viewWithTag在cellForRowAtIndexPath中的单元格中找到正确的控件!(我需要在每个单元格中设置若干项。) 那么,我的思路是否正确?我觉得我很难准确地找出哪个UISwitch改变了

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

但是,我已经准备好使用tag属性进行其他操作,即使用viewWithTag在cellForRowAtIndexPath中的单元格中找到正确的控件!(我需要在每个单元格中设置若干项。)


那么,我的思路是否正确?我觉得我很难准确地找出哪个UISwitch改变了它的值,所以我可以用它做一些有用的事情。

你的方法很接近。我在类似情况下所做的是创建单独的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
在:

Owner是单元格的代理,然后可用于在控制器中启动操作。确保将UISwitch连接到toggleValue操作,以便在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属性的使用。

我通过将UISwitch子类化修复了这一问题,如下所示:

@interface NamedUISwitch : UISwitch {
NSString *name;
}

它看起来很优雅(不需要索引数组),标记属性可以自由地执行任何它想要的操作


我读到您必须小心Objective-C中的子类化,尽管…

我已经编写了一个UISwitch子类,其中包含一个基于块的hander,用于值更改控制事件,这有助于跟踪哪个开关的值已更改。理想情况下,我们可以对组合而不是子类化做类似的事情,但这很适合我的需要

您可以这样使用它:

ZUISwitch *mySwitch = [ZUISwitch alloc] init];

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

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

我意识到我加入该党大约晚了三年,但我已经开发了一个解决方案,但没有子类化,我认为它更可取(更简单)。我使用的场景与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。这似乎是一种不必要的方法,因为乍一看,您所要做的就是识别交换机的superview,但ios7和早期版本的superview之间存在差异,因此这可以处理所有:

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

如何子类化UISwitch并向其添加字符串标识符?这会是糟糕的设计吗?嗯,你的方法的一个问题是我没有使用IB,所以我自己将所有控件添加到单元格的contentView中。然后,当我再次需要它们在表控制器中为显示的行设置它们的值时,我会使用viewWithTag将它们取回。这几乎就是问题所在,因为我已经在使用标记来识别更改了什么开关。使用笔尖,您只需连接一些插座。我错过了一些重要的东西吗?我现在要尝试对UISwitch进行子类化,尽管我不确定UISwitch是否构建为子类化。我建议深入IB,对整个UITableViewCell进行子类化,而不仅仅是UISwitch。我相信,从长远来看,它将产生更多可维护的代码。另外,一旦你通过IB/XCode创建了一个子类,它就真的变成了一个快照。我也做了同样的事情,我唯一的评论就是把名字变成一个属性。这是一个很好的方法,特别是对于迭代未知数量的开关。我很好奇为什么您在awakeFromNib和init中都使用
[self commonInit]
- (NSIndexPath *)indexPathForCellContainingView:(UIView *)view {
    while (view != nil) {
        if ([view isKindOfClass:[UITableViewCell class]]) {
            return [self.myTableView indexPathForCell:(UITableViewCell *)view];
        } else {
            view = [view superview];
        }
    }   
    return nil;
}