🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1833閲覧

cellForRowAt()内でdequeueReusableCell()にてUIButtonが再利用出来ない(nilになる)

mercy333

総合スコア1

TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/12/09 22:59

cellForRowAt()内でdequeueReusableCell()にてUIButtonが再利用出来ない(nilになる)

iOSアプリ開発初学者です。 SwiftでTodoアプリを作っています。
cellForRowAt()内でdequeueReusableCell()を用いてセル再利用をしていますが、
再利用前の状態のセルが残って描写されてしまい困っております。

知識が至らぬ点などあると思いますが、対応策をご教授いただけると幸いです。

発生している問題・エラーメッセージ

具体的にはTableViewCell内にUIButtonを配置しており、セル生成時に画像(初期値)をUIButtonに設定したいのですが、セル再利用時にUIButtonがnilになっていて参照できず設定が出来ません。
ただ、cellForRowAt()の後はUIButtonは存在はしているのか画像も表示されているし、タップ処理も実施できます。

  • TableViewの情報について説明します。

TableView内にUIButton(画像左側の○or✅マーク)とUILabel(料理をする等)を配置しています。

TableView

以下に、①期待するパターン/②異常パターンのキャプチャを貼ります。

####①セル追加時の正常パターン(期待する動作)
正常パターン

####②セル追加時の異常パターン(再利用前の情報が残る)
本事象となります。
チェック済みのセルを削除した後、セル新規追加を実施するとチェック済みの状態で生成されます。
※この時、後述ソースの★★★部分でnilとなっています。
イメージ説明

該当のソースコード

★★★部分でUIButtonがnilとなってしまう。

Swift

1 /* Todo内容リスト */ 2 var missionList = [String]() 3 4 /* Todoリストのチェック状況 true:達成 / false:未達成 */ 5 var isCheckList = [Bool]() 6 7 /* セルを生成時にcall **/ 8 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 9 // セルの取得(再利用) 10 let cell = missionTable.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) 11 12 // Todo内容をカスタムセルの Label(tag2)に設定 13 let cellLabel = cell.viewWithTag(2) as! UILabel 14 cellLabel.text = missionList[indexPath.row] 15 16 // カスタムセルのボタン(tag1)をunCkeckMarkに設定 17★★★ if (cell.viewWithTag(1) as? UIButton) != nil { 18 let cellButton = cell.viewWithTag(1) as! UIButton 19 20 // true/falseで画像切り替え 21 if (isCheckList[indexPath.row] == true) { 22 cellButton.setImage(UIImage(systemName: "checkmark.circle"), for: .normal) 23 } else { 24 cellButton.setImage(UIImage(systemName: "circle"), for: .normal) 25 } 26 27 // カスタムセルのボタンをタップした時にcallするメソッドを設定 28 // * チェック/アンチェックを切り替える 29 cellButton.addTarget(self, action: #selector(checkButton(_:)), for: .touchUpInside) 30 31 // カスタムセルのボタンのタグ値に行番号を保持 32 cellButton.tag = indexPath.row 33 } else { 34 debugLog("cell.viewWithTag(1) is nil.") 35 } 36 return cell 37 }

(補足)
TableViewCellのIdentifiler : "CustomCell"
TableViewCell配下の、
UIButtonにはTag:1
UILabel にはTag:2 を割り振っている

試したこと

Inspectorにてプロパティの確認は実施し、TableView周りの設定値(Tag値やセルIdentifierなど)に不備がないことを確認しました。

恐縮ですが他は特にできていません。
セル生成後は最初の描写はおかしくなれどUIButtonは存在しており、インスタンスの状態が不明なため。

補足情報(FW/ツールのバージョンなど)

Xcode : Version 12.2 (12B45b)

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TsukubaDepot

2020/12/10 01:43 編集

問題は、 (cell.viewWithTag(1) as? UIButton) != nil ということですが、画像の説明を拝見する限り あるセルを削除後、新たに項目を追加すると、チェック済みの項目ができてしまう。 という別の問題に言及されているように思えます。 これは、どちらとも生じている問題なのでしょうか。 なんとなく、tableView の delegate を使ったセルの削除と、実際にデータを保存している配列の削除の辻褄があっていないことが原因のような気もするのですが、そのあたりは大丈夫でしょうか。 もし、実行可能で再現できる程度のコードを提示していただいた方が、解決は早いかもしれません(カスタムセルの構造は説明で理解できています)。
MasakiHori

2020/12/10 02:36

debugLog("cell.viewWithTag(1) is nil.")が実行されているということで間違いありませんか?
mercy333

2020/12/10 03:53

Masaki Hori様 コメントありがとうございます。 YESです。ご認識のとおりです。
mercy333

2020/12/10 04:20

回答 TsukubaDepotさん コメントいただきありがとうございます。 >あるセルを削除後、新たに項目を追加すると、チェック済みの項目ができてしまう。 >という別の問題に言及されているように思えます。 >これは、どちらとも生じている問題なのでしょうか。 どちらとも生じています。 チェック済みの項目が出来てしまうと記載していましたが、説明不足でした。画面上はチェック済みアイコンが表示されているだけで、内部データ的には未チェックの状態です。 if (cell.viewWithTag(1) as? UIButton) != nil )ルート内で未チェックアイコンにsetImage()するはずか、nilのため出来ておらず、再利用前のアイコンが表示されている(=チェック済みアイコンで出てしまう)認識です。 > tableView の delegate を使ったセルの削除と、実際にデータを保存している配列の削除の辻褄があっていないことが原因のような気もするのですが 配列の整合性は確認して問題ありませんでした。 また、セル削除だけではなく、1画面に収まらない数のセルを作り、上下にスクロールして画面から消したり表示したりしても、同現象が発生しアイコンのチェック/未チェックが変わってしまいます。 ソースは提示出来るよう進めます。 (すみません出先のため、後ほど対応します。)
TsukubaDepot

2020/12/10 07:08

TakeOne さんご指摘の通りですね。 cellButton.tag に indexPath.row を代入してしまうと、意図しない動きとなってしまいます。
guest

回答1

0

ベストアンサー

何がしたかったのかわかりませんが、
cellButton.tag = indexPath.row
これをやったら、UIButtonのtagは1でなくなってしまいますよね。
そのセルを再利用したらcell.viewWithTag(1)はnilになると思います。

投稿2020/12/10 04:15

TakeOne

総合スコア6299

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TsukubaDepot

2020/12/10 08:00

この行の存在にまったく気づきませんでした...(カスタムクラスのプロパティと思ってた)。 しかも、これをやってしまうと、他の行で実行している viewWithTag が階層構造を追って探してしまうため、場合によっては実行時エラーが起きますね。
mercy333

2020/12/10 23:47

ご回答ありがとうございます。ご指摘の行が原因でした。 タグ値はセル再利用しても変わらないのですね…(タグ値リセットされるかと思い込んでいて、考慮不足でした) 助かりました。本当にありがとうございました。 以下は補足です。 なぜこんな事をしていたかというと、ボタン押下した際に自身が何番目の行かを知りたかったので、タグ値に行番号を持たせていました。私の使い方が悪かったです。 (参考にした情報) https://teratail.com/questions/136072
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問