2013-01-25 48 views
1

我有一个带有UISwitch作为accessoryView的UITableView。我的问题是,如果我切换其中一个开关,然后滚动以便将它切换到视图之外,它将返回到之前的状态。UISwitch在UITableView的滚动上不动摇

请参阅video

有谁知道为什么这可能是如何解决它?

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

- (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"]; 

} 

感谢您的任何帮助。

回答

1

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

让我从让你困惑的那个开始吧。 您根据toggle设置每个女巫的状态。 toggle的价值是从self.toggleArray排列。

迄今为止很好。 但是,如果某个值发生变化并且动作switchChanged被调用,那么您将更新self.filterDic,但不更新self.toggleView。当细胞变得可见cellForRowAtIndexPath被再次调用,将设置是基于self.toggleArray基于toggle至极值 下一次:

,这将导致该问题。那还有它的旧价值......你看到了吗?

你犯了这个错误可能是因为你还没有完全理解cell recycle机制。这可能是导致我发现的第二个问题的原因。让我试着解释一下。 iOS或cocoa分别尝试将视图单元对象分配为无需注册。这意味着将一个滚动到屏幕上的单元格添加到池中,在下次需要(类似)销售时可以重新使用它。所以每当需要一个新的细胞(一个变得可见),cellForRowAtIndexPath被调用。使用dequeueReusableCellWithIdentifier来获取单元格。如果该池中有一个单元用相同的重用标识符初始化,那么该单元(或其中之一)将返回给调用者。 在最近的iOS(分别为SDK版本)版本中,如果这些单元不存在,则将分配并返回一个新的单元。 (这就是为什么Murali的建议不能很好地工作) 在旧版本中,您必须在这些情况下检查单元格是否为零并且alloc/init为新的。

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

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

首先 - 检查单元是否被重新使用。只要检查开关是否已经在那里。为了做到这一点,你可以用一些不同于0的值来标记它,并用这个标签获取子视图。如果你没有得到它,那么这个单元格是新的,你必须创建所有额外的子类。

第二个 - 在用dequeueReusableCellWithIdentifier获取单元格之后,您总是可以擦除单元格中的所有子视图。这是最简单的解决方案,因为您不必更改现有代码。尽管如此,它并不是最高性能的解决方案。

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

+0

感谢您花时间回答。我希望尝试和实施2号,但我会记住其他人。如果我有时间,稍后再更改它。下次我肯定会以第三种方式做。再次感谢。像这样的事情对于新开发的人来说总是很清楚。 – Will

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; 
} 
+0

我刚刚尝试过这种方法,但我根本不添加UISwitch。 – Will

+0

@请检查编辑答案... – Murali

+0

我有。它仍然没有显示它们。你能否解释你想改变什么?谢谢 – Will