3

こんにちは、私のアプリで重大ではないかもしれないが奇妙な問題を見つけました。

私はviewControllerにスイッチを持っています。それをtheSwitchと呼びましょう。セルにデータを入力するとき、indexPath(0,0)にそのスイッチをアクセサリビューとして配置します。

スイッチの状態によって、セルのタイトルが変わります

//Code simplified for simplicity 
if(indexPath.section == 0 && indexPath.row == 0) {
     cell.textLabel.text = self.filtersActivatedSwitch.on ? NSLocalizedString(@"Filters activated", nil) : NSLocalizedString(@"Filters deactivated", nil);
     cell.accessoryView = self.filtersActivatedSwitch;
}

スイッチが押されると、このメソッドが呼び出されます

-(void)switchActivated {
     [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:VisibilityFilterTableViewSectionMasterFilter]];
}

メソッド cellForRowAtIndexPath でセルをデキューしようとすると、代わりに新しいセルが作成されるため、デッドロックが発生します (これはテスト済みで、リロードしたいセルと同じセルを使用した方が理にかなっていると思いました)。セルの構成スイッチはaccessoryViewとして追加されます...

ここがややこしいところです...

BadPirateの回答は、tableviewcellでlayoutSubviewが呼び出されたときを説明しています

layoutSubviews はいつ呼び出されますか?

-addSubview を指定すると、追加されるビュー、追加されるビュー (ターゲット ビュー)、およびターゲットのすべてのサブビューで layoutSubviews が呼び出されます。

同じことがremoveFromSupperview(仮定)でも起こるはずだと思うので、新しいセルにはlayoutSubviewが呼び出されます..それはaccessoryViewをチェックし、それがnilではないことを確認して、それを尻のサブビューに追加します。一方、古いセル(そのなんらかの理由でキューから取り出されなかったので、accessoryView をクリアできませんでした) removeFromSuperview が原因で layoutSubviews が呼び出されます (これも仮定)、accessoryView が nil でないことを確認し、スイッチをサブビューとして追加します...そして永遠に繰り返します。

私の質問は...テーブルビューが既にデキューされたセルを使用しないのはなぜですか? 2 つの tableviewcells が同じ accessoriesView を持っているという事実は明らかにアプリをクラッシュさせます。

または、アクセサリのビューを間違って使用していますか?

乾杯!

編集: これは prepareForReuse のコードです

- (void)prepareForReuse {
  [super prepareForReuse];

  for (UIView *view in self.contentView.subviews) {
      [view removeFromSuperview];
  }

  for (UIView *view in self.imageView.subviews) {
      [view removeFromSuperview];
  }

  self.textLabel.text = nil;
  self.detailTextLabel.text = nil;
  self.imageView.image = nil;
  self.imageView.tag = 0;
  self.accessoryView = nil;
}
4

1 に答える 1

3

セルは再利用されるため、画面外にスクロールされたセルは別の場所で再利用でき、追加したサブビューはそのまま残ります。特定の indexPath にアクセサリ ビューを追加する場合は、そこに「else」句を追加して、他のセルにそのビューを持たないように指示する必要があります。cellForRowAtIndexPath: で他に何をしているのかわかりませんが、私のテスト メソッドでは、prepareForReuse メソッドをまったく使用する必要はありませんでした。switch メソッドが起動したときにデッドロックが発生する理由がよくわかりませんが、reloadRowsAtIndexPaths:withRowAnimation: メソッドでアニメーションを UITableViewRowAnimationNone に設定すると、すべてが機能しました。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    if(indexPath.section == 0 && indexPath.row == 0) {
        cell.textLabel.text = self.filtersActivatedSwitch.on ? NSLocalizedString(@"Filters activated", nil) : NSLocalizedString(@"Filters deactivated", nil);
        cell.accessoryView = self.filtersActivatedSwitch;
    }else{
        cell.textLabel.text = self.theData[indexPath.row];
        cell.accessoryView = nil;
    }

    return cell;
}

-(void)switchActivated {

    [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}
于 2013-08-31T01:46:11.917 に答える