1

我有一个带有 UISwitch 作为附件视图的 UITableView。我的问题是,如果我切换其中一个开关然后滚动,以便将其从视图中移出,它会返回到之前的状态。

请看视频

有谁知道为什么会这样以及如何解决它?

这是添加切换视图并处理其操作的代码。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *CellIdentifier = @"POICell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier ];

    //set the cell text to the
    cell.textLabel.text = [self.catNames objectAtIndex:[indexPath row]];
    NSString *toggle = [self.toggleArray objectAtIndex:[indexPath row]];
    //add switch
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    //create an instance of the database oject
    DataBase * dataBase = [[DataBase alloc] init];

    //open the database connection
    [dataBase openDB];
    NSString *imageName = [dataBase getPinImageNameFromCatID:[self.catIDs objectAtIndex:[indexPath row]]];

    //get the root file path for the images
    NSArray   *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString  *documentsDirectory = [paths objectAtIndex:0];
    NSString *filePath = [NSString stringWithFormat:@"%@/pinImages/%@",documentsDirectory, imageName];

    //add image
    NSURL *imageURL = [NSURL fileURLWithPath:filePath];
    NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
    UIImage *image = [UIImage imageWithData:imageData];

    cell.imageView.image = image;
    NSLog(@"%@",[self.catIDs objectAtIndex:[indexPath row]]);

    UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
    cell.accessoryView = switchView;
    [switchView addTarget:self action:@selector(switchChanged: ) forControlEvents:UIControlEventValueChanged];

    if ([toggle isEqualToString: @"OFF"]) {
        [switchView setOn:NO animated:NO];
    }else{
        [switchView setOn:YES animated:NO];
    }
    return cell;
}

- (void) switchChanged:(id)sender {

    //get the switch that it was sent from
    UISwitch *switchInCell = (UISwitch *)sender;
    //get the cell it was sent from
    UITableViewCell * cell = (UITableViewCell *) switchInCell.superview;
    //get the row it was sent from
    NSIndexPath * indexpath = [self.inputTableView indexPathForCell:cell];
    //cast the indexpath to int
    NSInteger variable = indexpath.row;
    //set the filter as off in the user defualts.
    [self.filterDic setValue:switchInCell.on ? @"ON" : @"OFF" forKey:[self.catIDs objectAtIndex:variable]];
    //store the newdic in the user defualts
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    //save the dic to user defaults
    [prefs setObject:self.filterDic forKey:@"pinFilters"];

}

谢谢你的帮助。

4

3 回答 3

1

也许你的细胞正在被回收。

看看这里接受的答案:

iphone:uitableview:滚动时单元格的内容发生变化

于 2013-01-25T11:52:50.147 回答
1

请用这个方法。。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = @"POICell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UISwitch *switchView;
if (cell == nil)
{
    cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier ];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    switchView = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];//Change the frame 
    cell.accessoryView = switchView;
}
//set the cell text to the
cell.textLabel.text = [self.catNames objectAtIndex:[indexPath row]];
NSString *toggle = [self.toggleArray objectAtIndex:[indexPath row]];
//add switch

//create an instance of the database oject
DataBase * dataBase = [[DataBase alloc] init];

//open the database connection
[dataBase openDB];
NSString *imageName = [dataBase getPinImageNameFromCatID:[self.catIDs objectAtIndex:[indexPath row]]];

//get the root file path for the images
NSArray   *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString  *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:@"%@/pinImages/%@",documentsDirectory, imageName];

//add image
NSURL *imageURL = [NSURL fileURLWithPath:filePath];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];

cell.imageView.image = image;
NSLog(@"%@",[self.catIDs objectAtIndex:[indexPath row]]);

[switchView addTarget:self action:@selector(switchChanged: ) forControlEvents:UIControlEventValueChanged];

if ([toggle isEqualToString: @"OFF"]) {
    [switchView setOn:NO animated:NO];
}else{
    [switchView setOn:YES animated:NO];
}
return cell;
}
于 2013-01-25T11:53:08.330 回答
1

您的代码有两个问题(至少:)

让我从让你困惑的一个开始。您根据 设置每个女巫的状态toggle。的值toggle是从一个数组中提取出来的self.toggleArray

到目前为止还好。但是当一个值改变并且动作switchChanged被调用时,你更新self.filterDic但你不更新self.toggleView

这会导致问题:下次当单元格变为可见cellForRowAtIndexPath时,将再次调用它,并将基于togglewich设置值self.toggleArray。而且它仍然具有旧的价值观……你看到了吗?

你犯这个错误可能是因为你还没有完全理解细胞循环机制。这可能是导致我发现的第二个问题的原因。让我试着解释一下。iOS 或 cocoa 分别尝试将视图单元对象分配为必要的。这意味着从屏幕上滚动的单元格被添加到池中,下次需要(类似)销售时,可以从该池中重新使用它。因此,每次需要一个新的单元格(一个可见的)时cellForRowAtIndexPath都会被调用。在您使用dequeueReusableCellWithIdentifier. 如果该池中有一个单元格使用相同的重用标识符进行了初始化,那么那个(或其中之一)将返回给调用者。在最近的 iOS(分别为 SDK 版本)版本中,如果这些单元都不存在,则将分配并返回一个新单元。(这就是为什么 Murali 的建议也不能完美运行的原因)在旧版本中,您必须检查单元格中的 nil 并在这些情况下重新分配/初始化。

之后,您可以自由分配新的子视图对象,无论单元格是否被重新循环并且是否已经具有这些子视图。然后,您一次又一次地添加并添加和添加相同的子视图。

你怎么能解决这个问题?像往常一样,有几种处理方法:

首先 - 检查细胞是否被重复使用。只需检查 Switch 是否已经存在。为此,您可以使用一些不同于 0 的值对其进行标记,并使用此标记获取子视图。如果你没有得到它,那么这个单元格是新的,你必须创建所有额外的 subvies。

第二 - 您总是可以在使用dequeueReusableCellWithIdentifier. 这是最简单的解决方案,因为您不必将 mutch 更改为现有代码。虽然它不是最高效的解决方案。

第三 - 最优雅的解决方案可能是UITableViewCell每次要向单元格添加自定义元素时进行子类化。在这种情况下,它的 init 方法只会在创建时调用一次(而不是在重用时),您可以在其中以编程方式添加所有自定义子视图。当然,您可以设计单元格并在 IB 中添加所有子视图,就像对每个UIView对象一样。您cellForRowAtIndexPath只需要关心设置适当的值。

于 2013-01-25T12:22:07.180 回答