3

我正在尝试创建一个 UITableViewController 子类,为我提供 UITableView 和我的应用程序设置。重新加载有关更改 UISwtitch 状态的数据时遇到问题。

该表有 3 个部分:

第 1 节 - 一排不断

第 2 部分 - 第一行中的 UISwitch 使该部分包含 1 或 3 行(取决于 UISwitch 的状态)

第 3 部分 - 第一行中的 UISwitch 使该部分包含 1 或 3 行(取决于 UISwitch 的状态),但还有另一个 UISwitch 和其他行数据。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    switch ( section )
    {
        case 0:
            return 1;
            break;
        case 1:
            if ( limit_password_attempts )
                return 3;
            else 
                return 1;
            break;
        case 2:
            if ( lock_when_inactive )
                return 3;
            else 
                return 1;
            break;
        default:
            return 1;
            break;
    }  
}

第二部分和第三部分第一行中的那两个 UISwitch-s 分别在更改 BOOL

BOOL limit_password_attempts;
BOOL lock_when_inactive;

我的问题是当我在第二部分切换 UISwitch(例如)时,我希望我的第二部分再扩展 2 行,并填充新数据。它会扩展,但新单元格看起来不像我想要的那样。第二行成为下一节中第一行的副本(第三节为 UISwitch 的行),如果第三节之前没有扩展,则第三行正确返回,如果是,则此行变为第三部分第二行的副本。

所以我对单元格的自定义看起来像这样,我猜错误在这里的某个地方。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        
    UITableViewCell *cell = nil;
    static NSString *EnabledCellIdentifier = @"Enabled";
    cell = [tableView dequeueReusableCellWithIdentifier:EnabledCellIdentifier];
    
    if (cell == nil) 
    {
        cell = [[[UITableViewCell alloc] 
                   initWithStyle: UITableViewCellStyleDefault 
                 reuseIdentifier: EnabledCellIdentifier]
                    autorelease];
    
        cell.detailTextLabel.enabled = YES;
        
        switch ( indexPath.section )
        {
            case 0: // section 1
                cell.textLabel.text = @"Banks settings";
                break;
            case 1: // section 2
            {
                switch ( indexPath.row )
                {
                    case 0:
                    {
                        cell.textLabel.text = @"Limit passwords attempts";
                        UISwitch* actSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];
                        
                        [cell setEditingAccessoryView: actSwitch];
                        
                        [actSwitch setTag: indexPath.section];
                        [actSwitch addTarget: self
                                      action: @selector(actSwitchChanged:) 
                            forControlEvents: UIControlEventValueChanged];
                        
                        [self.view addSubview:actSwitch];
                        [actSwitch setOn:YES animated:NO];
                        [actSwitch setOn:NO animated:NO];
                        
                        actSwitch.on = NO;
                        [cell addSubview: actSwitch];
                        cell.accessoryView = actSwitch;
                        [actSwitch release];
                        break;
                    }
                    case 1:
                        cell.textLabel.text = @"Lock after 3 atempts";
                        break;
                    case 2:
                        cell.textLabel.text = @"Lock for 30 min";
                        break;
                    default:
                        break;
                }
                break;
            }
                
            case 2: // section 3
            {
                switch ( indexPath.row )
                {
                    case 0:
                    {
                        cell.textLabel.text = @"Lock when inactive";
                        UISwitch* pactSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];
                        
                        [cell setEditingAccessoryView: pactSwitch];
                        
                        [pactSwitch setTag: indexPath.section];
                        [pactSwitch addTarget: self
                                      action: @selector(actSwitchChanged:) 
                            forControlEvents: UIControlEventValueChanged];
                        
                        [self.view addSubview:pactSwitch];
                        [pactSwitch setOn:YES animated:NO];
                        [pactSwitch setOn:NO animated:NO];
                        
                        pactSwitch.on = NO;
                        [cell addSubview: pactSwitch];
                        cell.accessoryView = pactSwitch;
                        [pactSwitch release];
                        
                        
                        break;
                    }
                    case 1:
                        cell.textLabel.text = @"Lock when inactive for 20 min";
                        break;
                    case 2:
                        cell.textLabel.text = @"Unlock key";
                        break;
                    default:
                        break;
                }
                break;
            }
            default:
                NSLog(@"%d", indexPath.section );
                break;
        }
    }
    return cell;
}

看起来有一些对我隐藏的带有行数据的数组,即被填充的 onec,并且表控制器以某种方式更新表,具体取决于出现的行,仅更新它们。为什么在部分中添加行时会复制。这就像在数组中插入一个节点。我认为它必须推动细胞前进,而不仅仅是复制。我是否必须以某种方式删除行以进行这种表更新?我想我在这里遗漏了一些基本的东西。一些MVC概念?但是这里真的有必要有一个数据模型吗?为什么?如果是,那我该怎么做?

谢谢你的任何答案。祝你有美好的一天。


它在我的代码中。我只是没有在我的问题中写下来。切换 UISwtitch 后调用 reloadData 方法:

[pactSwitch setTag: indexPath.section];
[actSwitch addTarget: self
              action: @selector(actSwitchChanged:) 
    forControlEvents: UIControlEventValueChanged];

在 actSwitchChanged 方法中:

-(void) actSwitchChanged: (UISwitch*) pSwitch {
      
    if ( [pSwitch tag] == 1 ) //section 2
        limit_password_attempts = !limit_password_attempts ;
    else if ( [pSwitch tag] == 2 ) //section 3
        lock_when_inactive = !lock_when_inactive;
    [self.tableView reloadData];

}

所以 reloadData 确实改变了 viewTable 的内容,但它不是我期望的那样。

有任何想法吗?

4

3 回答 3

4

数据模型始终存在......即使它只是您的 UITableView 调用的一堆 if 语句。我认为这种区别导致了问题。

您的布尔值代表您的基础数据模型。与对数据模型的所有更改一样,您必须让表视图知道您的基础数据何时发生更改。

每当您更改其中一个布尔值时,请尝试添加以下调用。

[myTableViewController.tableView reloadData];
于 2011-02-02T18:10:48.163 回答
3

你是对的,你实施了错误的- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath。如果您正在寻找简单的方法来实现具有不同布局的单元格而无需子类化,UITableViewCell那么您需要,例如:

0) 阅读本文以深入了解 UITableView 编程

1) 方法为每个布局返回一种单元格

- (NSString*)typeOfCellForIndexPath:(NSIndexPath*)indexPath {
    NSString *ret = @"CellWithoutSwitch";
    if(indexPath.section != 0 && idextPath.row == 0) {
        ret = @"CellWithSwitch";
    }
    return ret;
}

2) 方法为每种类型返回一个单元格

- (UITableViewCell*)cellForType:(NSString*)aType {
    UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: aType] autorelease];
    cell.detailTextLabel.enabled = YES;
    if ([aType isEqualToString:@"CellWithSwitch"]) {
        // just copy of your code
        // this does not need here
        cell.textLabel.text = @"Limit passwords attempts";
        // this needs but with CGRectMake(...) insted of CGRectZero
        UISwitch* actSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];
        // this does not need
        [cell setEditingAccessoryView: actSwitch];
        // this needs but for switch tag you should use #define SWITCH_TAG 777
        [actSwitch setTag: indexPath.section];
        // this does not need here
        [actSwitch addTarget: self
                      action: @selector(actSwitchChanged:) 
            forControlEvents: UIControlEventValueChanged];

        // wrong part of code
        [self.view addSubview:actSwitch];
        // this does not need here
        [actSwitch setOn:YES animated:NO];
        // wrong part of code
        [actSwitch setOn:NO animated:NO];

        actSwitch.on = NO;
        // ok
        [cell addSubview: actSwitch];
        // wrong part of code
        cell.accessoryView = actSwitch;
        // ok
        [actSwitch release];
    }
}

3) 用路径配置单元格的方法

    - (void)cofigureCell:(UITableViewCell*)cell forIndexPath:(NSIndexPath*)indexPath {
        // just copy of your code
        switch ( indexPath.section )
        {
            case 0: // section 1
                cell.textLabel.text = @"Banks settings";
                break;
            case 1: // section 2
            {
                switch ( indexPath.row )
                {
                    case 0:
                    {
                        cell.textLabel.text = @"Limit passwords attempts";
                        /* this part of code replace with UISwitch* actSwitch = (UISwitch*)[cell viewWithTag:SWITCH_TAG];
                        UISwitch* actSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];

                        [cell setEditingAccessoryView: actSwitch];

                        [actSwitch setTag: indexPath.section];*/

                        [actSwitch addTarget: self
                                      action: @selector(actSwitchChanged:) 
                            forControlEvents: UIControlEventValueChanged];
                        /* all what you need now that cofigure an state of switch with limit_password_attempts variable - [actSwitch setOn:limit_password_attempts animated:NO];
// this is junk
                        [self.view addSubview:actSwitch];
                        [actSwitch setOn:YES animated:NO];
                        [actSwitch setOn:NO animated:NO];

                        actSwitch.on = NO;
                        [cell addSubview: actSwitch];
                        cell.accessoryView = actSwitch;
                        [actSwitch release];*/
                        break;
                    }
                    case 1:
                        cell.textLabel.text = @"Lock after 3 atempts";
                        break;
                    case 2:
                        cell.textLabel.text = @"Lock for 30 min";
                        break;
                    default:
                        break;
                }
                break;
            }

            case 2: // section 3
            {
                switch ( indexPath.row )
                {
                    case 0:
                    {
                        // look at previous configuration of switch
                        cell.textLabel.text = @"Lock when inactive";
                        UISwitch* pactSwitch = [[UISwitch alloc] initWithFrame: CGRectZero ];

                        [cell setEditingAccessoryView: pactSwitch];

                        [pactSwitch setTag: indexPath.section];
                        [pactSwitch addTarget: self
                                       action: @selector(actSwitchChanged:) 
                             forControlEvents: UIControlEventValueChanged];

                        [self.view addSubview:pactSwitch];
                        [pactSwitch setOn:YES animated:NO];
                        [pactSwitch setOn:NO animated:NO];

                        pactSwitch.on = NO;
                        [cell addSubview: pactSwitch];
                        cell.accessoryView = pactSwitch;
                        [pactSwitch release];


                        break;
                    }
                    case 1:
                        cell.textLabel.text = @"Lock when inactive for 20 min";
                        break;
                    case 2:
                        cell.textLabel.text = @"Unlock key";
                        break;
                    default:
                        break;
                }
                break;
            }
            default:
                NSLog(@"%d", indexPath.section );
                break;
        }
    }

4)最后一个方法的实现

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

    UITableViewCell *cell = nil;
    // get type for indexPath
    static NSString *EnabledCellIdentifier = [self typeOfCellForIndexPath:idextPath];
    cell = [tableView dequeueReusableCellWithIdentifier:EnabledCellIdentifier];

    if (cell == nil) 
    {
        // create a cell with needed type
        cell = [self cellForType:EnabledCellIdentifier];
    }

    // cofigure the cell
    [self cofigureCell:cell forIndexPath:indexPath];

    return cell;
}
于 2011-02-03T22:26:18.877 回答
0

盖伊,谢谢你的回答。它帮助了我,现在当我更改 UISwitch 条件时,表格重新加载正确。但是我必须更改 uiswitch 的标签,因为我确实需要区分我在actSwitchChanged方法中处理的 UISwitch 类型,以了解它是limit_password_attemptslock_when_inactive

我想这不会引起将来的问题吗?我的意思是,SWITCH_TAG 在这里被覆盖。而且,为什么我需要#define SWITCH_TAG 777没有更好的方法来标记它?为什么是 777?

                 cell.textLabel.text = @"Limit passwords attempts";
                 UISwitch* actSwitch = (UISwitch*)[cell viewWithTag: SWITCH_TAG];
                 [actSwitch setTag: indexPath.section];
                 [actSwitch addTarget: self
                               action: @selector(actSwitchChanged:) 
                     forControlEvents: UIControlEventValueChanged];
                 [actSwitch setOn:limit_password_attempts animated:YES];

我还有更多问题:我的程序现在运行良好,但是,我不明白发生了什么变化。我添加了更多方法:cellForType:cofigureCell:forIndexPath:,但它们所做的一切实际上与以前版本的cellForRowAtIndexPath:.

那么..这里发生了什么变化以使其正常工作?:)

于 2011-02-04T07:44:29.767 回答