1

私は、accessoryView として UISwitch を持つ UITableView を持っています。私の問題は、スイッチの1つを切り替えてからスクロールすると、スイッチが表示されなくなり、以前の状態に戻ることです。

ビデオをご覧ください。

これがなぜなのか、それを解決する方法を知っている人はいますか?

これは、スイッチ ビューを追加し、そのアクションを処理するコードです。

- (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

コードには2つの問題があります(少なくとも:)

あなたを混乱させているものから始めましょう。に基づいて各魔女のステータスを設定しますtoggle。そして、の値toggleは配列からのtankenself.toggleArrayです。

これまでのところ元気です。ただし、値が変更されてアクションswitchChangedが呼び出されると、更新されますが、更新されself.filterDicませんself.toggleView

そして、これは問題を引き起こします:次にセルが表示されるようになるcellForRowAtIndexPathと、が再び呼び出され、に基づいて値が設定さtoggleself.toggleArrayます。そして、それはまだ古い値を持っています...分かりますか?

おそらく、細胞のリサイクルメカニズムをまだ完全に理解していないために、この間違いを犯しています。そして、それがおそらく私が特定した2番目の問題の原因です。説明してみましょう。iOSまたはcocoaは、それぞれビューセルオブジェクトを必須として割り当てようとします。つまり、画面からスクロールオフするセルがプールに追加され、次に(同様の)販売が必要になったときに再利用できます。したがって、新しいセル(表示されるセル)が必要になるたびにcellForRowAtIndexPath呼び出されます。を使用してセルをフェッチするWihindequeueReusableCellWithIdentifier。同じ再利用識別子で初期化されたセルがそのプールにある場合、そのセル(またはそれらの1つ)が呼び出し元に返されます。最近のiOS(それぞれSDKバージョン)バージョンでは、これらのセルが存在しない場合、新しいセルが割り当てられて返されます。(そして、それがMuraliの提案も完全に機能しない理由です)古いバージョンでは、セルのnilをチェックし、その場合は新しいonをalloc/initする必要がありました。

その後、セルがリサイクルされ、すでにそれらのサブビューがあるかどうかに関係なく、新しいサブビューオブジェクトを自由に割り当てることができます。次に、同じサブビューを何度も追加して追加します。

どうすればこれを解決できますか?いつものように、それに対処するいくつかの方法があります:

最初-セルが再利用されたかどうかを確認します。スイッチがすでに存在するかどうかを確認してください。そのためには、0とは異なる値でタグを付け、このタグでサブビューをフェッチできます。取得できない場合は、セルが新しく、追加のサブビューをすべて作成する必要があります。

2番目-セルを取得した直後に、セルからすべてのサブビューをいつでも消去できますdequeueReusableCellWithIdentifier。mutchを既存のコードに変更する必要がないため、これが最も簡単な解決策です。ただし、これは最もパフォーマンスの高いソリューションではありません。

3番目-最も洗練された解決策はUITableViewCell、セルにカスタム要素を追加するたびにサブクラス化することです。その場合、そのinitメソッドは作成時に1回だけ呼び出され(再利用時には呼び出されません)、そこですべてのカスタムサブビューをプログラムで追加できます。もちろん、すべてのオブジェクトでできるように、セルを設計してIBにすべてのサブビューを追加することもできUIViewます。適切cellForRowAtIndexPathな値を設定するためだけに注意する必要があります。

于 2013-01-25T12:22:07.180 に答える
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 に答える