🔰 はじめに
はじめまして。株式会社レコチョク NX開発推進部 プロダクト開発第2グループの上野です。
2025年4月に新卒で入社し、9月より「PlayPASS」のiOSエンジニアを担当しています。
趣味はポケモンカードで、先日有明GYM-EXで2日間に渡って開催された公式大会では、個人戦7戦中5勝2敗、チーム戦7勝0敗で、合計12勝2敗という好成績を残しました。夏のよい思い出です。
配属前のエンジニアOJTでは、SwiftUIとUIKitのそれぞれで音楽アプリのホーム画面のモックを開発しました。まずはSwiftUIから実装を進めたのですが、「データと表示がそのままつながる」宣言的なフレームワークであったため、Swift初学者の私でも直感的にコードを書けました。
一方、UIKitでは「データと表示とイベントがわかれる」命令的なフレームワークで、各コードが複数ファイルをまたぎ、その内容を理解しないまま書いてしまいました。
本記事では、そのUIKitについて理解を深めるために、整理して解説していきます。
👞 UIKitでつまずいた2行のコード
そもそもUIKitには、レイアウトやデータ更新を制御しやすくするための4つのコンテナView(UICollectionView、UITableView、UIStackView、UIScrollView)があります。今回のOJTではUICollectionViewを用いて実装しました。
Appleの公式チュートリアルやYouTubeの動画を参考に、自力で勉強を進め、以下のコードを書きました。
collectionView.dataSource = self collectionView.delegate = self |
対象のViewControllerに、形式的に書いてしまったことで「この2行のコードは何をしているのか?」という疑問を残してしまいました。SwiftUIではこうしたコードを書く必要がなかったからです。
この2行のコードの理解を深めるため、本記事では、次の項目について解説していきます。
- UICollectionViewとは何なのか
- DataSourceとDelegateはどういう役割を持つのか
- 責務がわかれている理由はどうしてなのか
🤔 UICollectionViewとは
UICollectionViewとは、「複数のアイテムをグリッドやリスト形式で効率よく表示させるためのUI部品(View)」です。
例えば、写真アプリのサムネイル一覧や音楽アプリのアルバムジャケット一覧など、大量のアイテムを並べて表示する場面で活用されます。
このとき、アイテム1つ分を表すのがUICollectionViewCell(以降、セルと表記)です。セルには、写真やテキストなどを自由に配置できます。
また、UICollectionViewでは「表示中のセルだけがメモリに読み込み、画面外のセルは再利用する」仕組みがあります。そのため、大量のアイテムを扱うアプリでも軽快に動作します。
しかし、UICollectionView自体は「空の箱」でしかありません。
- どのセルにどのデータを表示させるか
- セルがどのように動作するか
これらを決めるのが、DataSourceとDelegateです。
📊 DataSourceの役割(何を表示するか)
DataSourceは「UICollectionViewにどのデータを、いくつ表示するか」を伝える役割を持つものです。UICollectionViewでは、オブジェクトがUICollectionViewDataSourceというプロトコルに準拠している必要があります。
UICollectionViewはこのプロトコルを通してアイテム数(箱にいくついれるか)や各セルの内容(その中身は何か)を知り、セルを描画します。このプロトコルがないと、UICollectionViewが描画できないため、設定は必須です。
代表的なメソッドは以下の2つです。
- collectionView(_:numberOfItemsInSection:)
func collectionView( _ collectionView: UICollectionView, numberOfItemsInSection section: Int ) -> Int |
このメソッドは、セクション内のアイテムの数(Int)を返します。返り値が5であれば、セクション内に5つのアイテムがあることを指しています。
- collectionView(_:cellForItemAt:)
func collectionView( _ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath ) -> UICollectionViewCell |
このメソッドは、指定した位置のセルを作成、または、再利用して返します。
例えば「5個のアルバムを表示する」のであれば、最初のメソッドでアイテム数である5を返し、次のメソッドで1つずつセルを作って渡します。
DataSourceを使うことで、次のようなメリットがあります。
- データとUIの管理をわけられる
- データを差し替えるだけで表示内容を変えられる
🤝 Delegateの役割(どう動くか)
Delegateは「UICollectionViewに対するユーザー操作や、セルやレイアウトの見た目や動きの制御」を担当するものです。UICollectionViewでは、オブジェクトがUICollectionViewDelegateというプロトコルに準拠している必要があります。
UICollectionView自体はセルの表示に集中し、タップやスクロールとったユーザー操作の処理は、Delegateに「任せる」仕組みになっています。こちらのプロトコルは設定しなくてもセルの表示自体は可能です。
代表的なメソッドは以下のとおりです。
- collectionView(_:didSelectItemAt:)
func collectionView( _ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath ) |
このメソッドは、セルがタップされたときに呼ばれます。例えば、リスト表示されている楽曲をタップしたとき、プレイヤー画面に遷移するように、どのような画面に遷移するのかなどを決める処理をします。
- collectionView(_:didDeselectItemAt:)
func collectionView( _ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath ) |
このメソッドは、セルの選択が解除されたときに呼ばれます。例えば、プレイリスト作成のチェックボックスで、一度選択したチェックを外したいといった処理をします。
- collectionView(_:shouldHighlightItemAt:)
func collectionView( _ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath ) |
このメソッドは、セルがタッチダウンされたとき(指が画面に触れたとき)に呼ばれ、そのセルをハイライトにするかどうかを決定します。例えば、セルをタップしたときに背景色を変えたい場合に使用します。
DataSourceは、UICollectionViewが「何を表示すればよいか」を質問する相手であることに対して、Delegateは、UICollectionViewが「ユーザー操作や表示のふるまいをどうすればよいか」を相談する相手です。
Delegateを使うことで、次のようなメリットがあります。
- ユーザー操作に応じた処理を柔軟に追加できる
- スクロールやセル選択などのイベントを個別に制御できる
DataSource / Delegateメソッドは、開発者が直接呼ぶことはほとんどありません。これらはUICollectionViewが内部で必要に応じて自動的に呼び出す仕組みになっています。
冒頭で書いたコードは、UICollectionViewに「データの提供は誰に聞けばいいか」「ユーザー操作の処理は誰に任せればいいか」を登録している部分です。
collectionView.dataSource = self collectionView.delegate = self |
ここで selfを代入しているのは、この画面を管理しているViewControllerが、DataSourceとDelegateの両方の役割を担うからです。 self以外に専用のクラスを用意して任せることもできますが、ViewControllerがまとめて担うことが一般的です。
一方、SwiftUIでは、ビューがデータの表示とユーザーの操作に対する反応を一元的に管理しているため、これらのプロトコルの設定は不要です。
📜 責務がわかれている理由
DataSourceが「何を表示するか」を、Delegateが「どう動くか」を担当しています。このように「責務をわける」という設計は、開発を進める上で多くのメリットがあります。
1. コードの見通しが良くなる
それぞれが別の処理を担当しているので、1つのクラスやメソッドが肥大化することを防ぎます。
もしデザインや表示処理、動作処理が交互に書かれていれば、どこを直せばよいかがわかりにくくなります。
2. 再利用や拡張がしやすい
DataSourceとDelegateがわかれていることで、同じデータでUIや動作を柔軟に切り替えることができます。
例えば、同じDataSourceを使いながら、
- リスト形式で表示する
- グリッド形式で表示する
といったレイアウトの変更が簡単です。
また、Delegateを差し替えることで、
- セルを「選択専用」にする
- タップしたら「詳細画面に進む」
- 長押ししたら「編集モードに入る」
といった動作のバリエーションを加えられます。
3. テストや保守に有利
DataSourceとDelegateが別々になっていることで、テストや保守の観点でもメリットがあります。
- DataSourceで「正しい数のセルが表示されているか」を検証
- Delegateで「タップ時に正しい処理が動くか」を検証
このように表示と動作を独立して確認できるため、コードが複雑になっても責務の切り分けを維持しやすくなります。
🗒️ まとめ
この記事ではUICollectionViewにおけるDataSourceとDelegateについて解説しました。
- UICollectionViewは、大量のデータを効率的に表示するUI部品。セルを再利用することで、軽快に動作する。
- DataSourceは「何を表示するか」、Delegateは「どう動くか」を担当し、責務をわけている。
- 責務をわけることで、コードが見やすくなり、再利用性や拡張性が向上する。
UIKitを学び始めた当初は、知らない単語や仕組みが多く苦手意識がありました。しかし、一つずつ理解することで、適切なコードを書くことができるようになりました。
この記事でUICollectionViewの理解がより深まれば幸いです。
📚️参考資料
- UICollectionView | Apple Developer Documentation
- UICollectionViewDataSource | Apple Developer Documentation
- UICollectionViewDelegate | Apple Developer Documentation
- UICollectionViewDataSourceについて解説 – JCB Tech Blog
- SwiftにおけるDelegateとは何か、なぜ使うのか #iOS – Qiita
- UICollectionView(UITableView)のセルの選択状態を制御しよう
- UICollectionViewのセルの強調・選択時にセルの見た目を変化させる #Swift – Qiita