iOS App Dev Tutorials(UIKit編)学習メモ

ここで紹介されていた、iOS App Dev TutorialsのUIKit側の学習メモ。
UIKitの公式チュートリアルは現状ここのページしかない認識。コースの内容的にSwiftUI側もやったほうが良さそうだが、UIKitを学ぶことがこちらの目的なためとりあえずここだけ。

Getting started with Today
このモジュールについて
- Appleアプリ開発が初めてなプログラミング経験者向けのページ
- 先にSwift言語の公式ドキュメントで基礎は確認しておくこと
UIKitとは?
- Appleアプリを作成するためのフレームワーク
- iOS13より前(※SwiftUIが使えない)をサポートする場合は必要
- Auto Layoutを使って、あらゆるデバイス向けのUIを作成出来る
- 公式ドキュメントだけでなく、コミュニティのサポートが手厚い
- SwiftUIとの統合も簡単に出来る
コースで作るアプリについて
- リマインダーリスト
- 作成したリマインダーの一覧が表示
- doneボタンを押すことでリマインダーを完了できる
- セグメントコントールで今日、今後、すべての切り替えが出来る
- +ボタンで追加ページに遷移できる
- リマインダー詳細ページ
- タイトル・日付・時間・注釈が見れる
- editボタンでここは変更できる
- リマインダー追加ページ
- 新規でリマインダーを追加できる
- 追加した後は一覧画面にすぐ反映できるようにする
成功までのTips
- コードを書き進めることで学習すること
- 最新バージョンのXcodeがインストールしてからコースを開始すること

Creating a list view(〜collection view controllerの追加まで)
プロジェクトの作成
- プロジェクトの作成画面でinterfaceを「Storyboard」を選択すると、UIKitのアプリを作成出来る
collection view controllerの追加
- View controllerとは?
- 画面の管理、更新を担う
- 複数のView controllerで画面間の橋渡しを行う
- 今回はそのView controllerの1つ、collection view controllerを使う
- データの集まりを表示するのに使う。
- グリッド表示、行(列)表示、テーブル表示などいろんな表示の仕方が出来る。
Xcode15でのStoryboardの注意点
2箇所ドキュメントだけでは分からなかった箇所があったのでメモ。
- デフォルトで設定されているView controllerの削除
In Main.storyboard, delete View Controller Scene from the document outline.
とあるが、
上記スクショの状態でdeleteボタンを押すと削除出来る。
- Libraryアイコンが見当たらない
Click the Library icon in the toolbar, and search for a collection view controller.
とあるが、ドキュメントにはアイコンのスクリーンショットがなく初見ではわからない。
Xcodeの画面右上にいるこのスクショの+アイコンをクリックすると出せる。Shift + Command + LでもOK。
(参考)

Creating a list view(〜ページの終わりまで)
Create a reminder model
- 画面に表示するリマインダーのモデルの定義
-
#if DEBUG
はアプリが開発モードになっているときのみ使える箇所を定義出来る
Configure the collection as a list
- 一覧の表示ビジュアルの設定
- iOS 14から使用できるUICollectionViewCompositionalLayoutを使って定義
- 今回のUICollectionLayoutListConfigurationを使った設定については以下の資料が詳しい
Configure the data source
- リストに表示する内容とUIの設定
- UICollectionView.CellRegistration
- リストのセル(=1行)にどのように表示するかを登録します
- この後に書くDataSourceの登録のために必要
- DataSource
- UICollectionViewに表示するデータを提供します
- ただしここではまだ画面に反映はしておらず、真っ白なままです。
- データの表示の調整役に近い。
Apply a snapshot
- ここでようやく画面にリストが表示されます。
- snapshot = ある時点での表示するデータのこと
- NSDiffableDataSourceSnapshotを使って、実際のデータをUICollectionViewに渡す
- for文とmap文の比較は以下のサイトが詳しい
- このsnapshotにサンプルデータを登録 -> datasourceにsnapshotを適当 -> UICollectionViewのdatasourceにセットすると画面の表示が出来る

Adopting collection views
- 前節でやったことの復習と補足
- ここからはリストに表示する情報を追加して、リマインダーの詳細が変更されてもリストに常に反映できている仕組みを作っていく
余談
ここまでやったUICollectionViewを深められそうなページを見つけた

Displaying cell info(〜Format the date and timeまで)
- ここではリマインダーのリストの見た目を整えていく
- Startererフォルダを使ってチュートリアルをやっていく。フォルダは以下アイコンからダウンロード出来る。
Format the date and time
- リストに出す日付と時間の表示を整える
- extension文を使って、Swift標準のDate型を拡張させて、表示を整えてくれるメソッドを定義し、使えるようにする
https://www.swiftlangjp.com/language-guide/extensions.html - リマインダーの日付今日だった場合、“Today at 3:00 PM” それ以外は“Oct 22 at 3:00 PM”みたいな表記になる
文法メモ
isDateInToday(_:) メソッド
与えられた日付が今日かを判定します
NSLocalizedString(_:comment:)メソッド
調べたけど、出てこなかった。こっちのメソッドと同一ということでいいのかな?
今は別のメソッドが推奨されているぽいが、Apple公式からアンサーがないので真意不明。
formatted(date:time:) メソッド
iOS15から使えるようになった指定した方式の時間表記を返してくれるメソッド。ここの公式ドキュメントが詳しいです。
formatted(_:)メソッド
2回目に出てくるformattedメソッドはこっち。同じくiOS15から使えるようになった。こちらは日付・時間に限らず細かい時間表記が設定できるのが特徴。
String(format:)メソッド
テンプレート文字列に指定した値を埋め込めた文字列を返すメソッドです。ここの記事が詳しいです。
Organize view controllers
- 前チャプターで作成したUICollectionView.CellRegistrationのリファクタリングがメイン
- リストに前節で作成したdayAndTimeTextプロパティを使った時間表記を追加
(備忘録)Xcode15だと出たエラーメモ
- Starterフォルダに入っているUIColor+Today.swiftでエラーが出る
追加したところこんな感じのエラーが出た。どうやらextensionでの定義がなくてもAssetsに入っていればそのまま呼び出せるようになったみたい。

Displaying cell info(最後まで)
Change the cell background color
UIBackgroundConfigurationを使いリスト項目の背景色を設定します。
Display the reminder complete status
文法メモ
UICellAccessory
リストの項目にボタンやアイコンといったaccessoryを置くことが出来ます。accessoryの配置はいじることが出来ず、右端に置かれます。配置や見た目をカスタマイズしたい場合は後述のcustomViewで定義する必要があります。
なおdisclosureIndicatorはこんな感じのアイコンを返します。ページ遷移で使うアイコンです。
customView(configuration:)
UICellAccessory.CustomViewConfigurationで定義されたカスタムなaccessoryを返します。
UICellAccessory.CustomViewConfigurationを使ったaccessoryの作り方についてはここの記事が詳しいです。
UIImage
画像を表示出来ます。概要はここのサイトが詳しいです(objective-cで書かれておりちょっと古いですが、おおよその掴めると思う)。
今回はiOS13から使用出来るinit(systemName:withConfiguration:)を使って定義されている。SF Symbolsに定義されたシステムアイコンを設定にそったサイズや色などで表示出来る。
アイコンは
- リマインダーがdoneがtrueだった場合は内側が塗りつぶされたアイコン
- リマインダーが逆にdoneがfalseだった場合は塗りつぶされていないアイコン
UIButton
ボタンを表示します。概要はここのサイトが詳しいです。setImageに関する解説も掲載されています。
なおデフォルトでは色が青になってしまうため、tintColorを使って任意の色に変更している。

Making reminders identifiable
※ここからいろんな箇所を修正するので、差分を見やすくするためにもgitが使えるなら始める前に一度コミットしたほうがいいかも。
いよいよタップしてリストのアイコンを切り替える処理を入れていきます。
Make the model identifiable
- ここではReminderモデルをIdentifiableな構造体に変更させる
文法メモ
Identifiable
iOS13から使用できるようになった。SwiftUIでもお馴染みの存在。セットすると一意なIDを持つ構造体となる。
UUID().uuidStringを使ってIDを生成できる。
Create functions for accessing the model
- ここではリマインダーを簡単に取得したり、更新出来るメソッドを組む
文法メモ
firstIndex(where:)
配列から条件にあてはまる1番目の要素を返すメソッド。
ただ配列とfirstIndexを繋げずに、firstIndexだけで出来ている理由が調べてもわからなかった。
reminders.indexOfReminderで定義出来るようにするため?もう少しextension周りを学習しないと。
Create functions for accessing the model
- ここではリマインダーのボタンクリックイベントを作成する
- iOSではこのようなクリックなどのボタンイベントをbutton actionと呼ばれる
文法メモ
toggle()
SwiftUIでもよく出てくるBoolean値を逆の値に変更するメソッド。スイッチを押すみたいな感じです。
@objc
Objectctive-cで書かれた古いAPIを扱うためのメソッド属性。詳しくは次の節で。
Wire a target-action pair
- ここでは前節で作成したボタンクリックイベントがリマインダーのボタンのクリックで出来るように設定していきます
- クリックでリスト項目にセットされたReminderクラスは更新されるようになったが、まだ画面の表示に反映されない。反映させるのは次節。
文法メモ
addTarget(_:action:for:)
パーツ(今回はボタン)にイベントを追加出来るメソッドです。
ちなみにiOS14からはaddActionというものでもう少し簡単に記載できるみたい。
今回は#selectorの中に前節で作成したdidPressDoneButtonメソッドを入れています。#selectorとdidPressDoneButtonメソッドを@objcで定義した理由については以下の記事に平易な文章で書かれています。Objective-Cが主流だった時代を知らない人間にとってはこういった記事はとても助かります。
Update the snapshot
- 前節でReminderクラス自体を更新しても画面の表示に反映されないことがわかった
- これはUICollectionViewのDataSourceにセットしているSnapshotが更新されていないため。更新するための実装を本節で行う
文法メモ
reloadItems(_:)
これを使うと1セル(今回だとリマインダーのリスト項目)にリロードをかけてその範囲だけsnapshotが更新される。
ただしアプリの初期表示時のリストはもちろん空っぽなので、今回はisEmptyで動作しないよう避けている。
ちなみにiOS15以降ではもう少し挙動が改善された方法が使えるらしい。
Make the action accessible
Preview using the Accessibility Inspector
残る2節はアクセシビリティに関する節で、UIKitの本筋からは離れるためここはざっくりとした概要に留める。
わかりづらかった箇所のメモ
Accessibility Inspectorの場所
スクショの場所から開ける。開かれるウィンドウも小さいので初見は気づきにくいかも。
調べている様子はこんな感じになる。

Displaying reminder details
本ページではリマインダーの詳細画面を作っていく。
Create a reminder view
ここではリマインダーの詳細画面ようのViewControllerを作っていく。
文法メモ
画面に出すUICollectionViewCompositionalLayoutの組み方はこれまでのコースでやってきたリスト画面のときと同じです。
UICollectionLayoutListConfiguration.Appearance.insetGrouped
UITableViewのものですが、表示の設定についてはここが参考になります。
Create an enumeration for rows
ここではenum文を使ってリマインダーの詳細画面の内容を1行ずつ表示できるように行ごとにどのデータを埋め込むか決めていきます。
文法メモ
Hashable
これまでIdentifiableという似た構造体が出てきましたが、Identifiableがidを持った方であるのに対して、Hashableは構造体そのものにハッシュ値を持ちます。
そのため今回のようにリスト形式で表示させたい場合に有効です。
Set up the data source
ここではリマインダーの詳細画面のdatasourceのセットを行います。やり方はリスト画面と同じで、セットするのが前節まで作成したenumを使う程度の違いです。
Set up a snapshot
リマインダーの詳細画面のsnapshotのセットを行います。ここもやり方はリスト画面と同じです。
snapshot.appendItemsのところでenumを使う程度の違いです。
Display the detail view
いよいよリスト画面から詳細画面の遷移を実装し、詳細画面を見れるように実装していきます。
文法メモ
collectionView(_:shouldSelectItemAt:)
リストのセルを選択したときの挙動を記載できるみたいだが、delegateはまだ理解できてないので以下の記事を見てもよく理解できなかった。。。
Navigation Controller
他画面の遷移を可能にするController。View Controllerを囲うことで使用できる。
Style the navigation bar
遷移は出来るようになったので、今度は戻るボタンがあるナビゲーションバーのスタイル指定をしていく。
スタイル指定で使用しているAppearanceについてはこちらの記事がわかりやすかったです。
スタイル指定メモ
コースだとダークモードでスクショが置かれていて、実際どんな感じにスタイリングされていなかったのかよくわかなかったため、少しずつやったスクショをメモっておきます。
Step5まで
最後まで

Getting ready for editing
※ここから少し難しくなっていく印象を受けました。ゆっくりでいいので出来る時に少しずつ進めることをオススメします。またコード差分を見るためにセクションごとにgitコミットを打っておくのもいいでしょう。
ここでは前回作成したリスト詳細ページにedit(編集)モードを追加し、リマインダーを編集できるように実装していきます。
Create sections for an editing mode
まずeditモード用のセクションを作成していきます。
- モードの切り替えのためSectionというenumを作成
-
.view
: 詳細ページが閲覧モードのときのセクション。なにも文字は置かないので空文字になっていうr -
.title
/.date
/.notes
: 逆にeditモードのとき出すセクション。それぞれタイトル・日付・注釈のセクションのタイトルをセットします。
-
文法メモ
isEditing
画面がeditモードか返します。UICollectionControllerはUIViewControllerに属しているので、そのまま使用できます。
init(rawValue:)
enum型のインスタンスを作成します。rawValueに探したい要素を指定することでその要素のインスタンスを引っ張ってくることが出来ます。SectionがInt型なので、今回はIndexPathから取っているのかな?
Configure the view and editing modes
ここではモード切り替えのためのリファクタリングを行います。具体的には以下のことを行っています。
- snapshot更新メソッドを閲覧モード・編集モードの2つに分離
- cellRegistrationHandlerにモード切り替えで表示を切り替えるロジックを入れる(ここではまだ既存の閲覧モードだけ)
Add an edit button
いよいよ詳細画面の右上にeditボタンを設置しておきます。
最終的にeditボタンを押すことでdatasource/snapshotを切り替え編集モードに画面が表示されるようになります。
- iOSでは画面右上のEditボタンを押すとDone(完了)ボタンが自動で表示されます。逆のパターンも一緒です
- ただしボタンを切り替えても画面の切り替えはまだ起こりません
文法メモ
rightBarButtonItem
画面上のナビゲーションバー(今回だと詳細画面にいる大きくReviewと書かれた欄です)の右端に設置するボタンを指定します。今回は後述のeditButtonItemを置きます。
editButtonItem
Editボタン(押すとDoneボタンになる)そのものになります。
setEditing(_:animated:)
ググるとUITableViewの方がヒットしますが、今回はUICollectionViewControllerなのでUIViewControllerの方を使います。
EditもしくはDoneボタンを押したときのロジックを記載します。
Show headers in editing mode
いよいよeditモードのとき画面が切り替わるように実装していきます。まずはヘッダー部分から実装していきます。
文法メモ
firstItemInSection
画面にある各セクションにそれぞれ登録されているitemの最初の要素をヘッダーとして表示させることが出来ます。

Managing content views
これから実装していく、editモードのUIの書き方・リマインダーの更新の管理をどうやって実現していくかについての概要が記載されています。
カスタムなcontent view / UIContentConfigurationについてはこちらの記事がわかりやすいです。

Using content views
いよいよ編集モードのパーツを設置していきます。前コースで触れられていたUIContentConfigurationを使って編集欄を作っていきます。
Extract configuration methods
これから編集欄を作っていくのに備えて、まず既存のUIContentConfiguration定義のリファクタリングを行っていきます。
Create a reusable layout function
編集欄それぞれに共通で使用するlayoutを組んでいきます。
※まだ編集欄を画面に表示させていないためAutoLayoutに慣れていない初心者にはコードの意図がわかりづらいと思います。ここは画面に表示させることが出来た後で再度見返してもいいと思います。
Create a custom view with a text field
タイトルのテキストフィールドのレイアウトを組んでいきます。
文法メモ
UIView
画面表示を管理する最も基本的なクラスです。UIKitで使用するUIなんとかの名前のクラスはこれがベースになっています。
- intrinsicContentSize
画面に出す最低のサイズとなります。画面パーツごとにサイズは決まっているのですが、こちらの記事が詳しいです。
UITextField
1行のテキスト表示・入力が出来るテキストフィールドの画面パーツです。
※複数行を扱う場合はUITextViewというまた別のパーツを使うようになります。
- clearButtonMode
テキストフィールドの右端に出来るクリアボタン(丸い❎ボタンです)の表示を指定できます。今回は.whileEditing
となっておりその名の通りテキストの入力中だけボタンが出るように指定しされています。
Conform to the content view protocol
テキストフィールドにUIContentConfigurationをセットできるように下準備を勧めていきます。
ヘッダーやリスト画面のときはcell.defaultContentConfiguration()
として標準で使用できるUIContentConfigurationを使って済ませていましたが、ここから追加している画面パーツは独自のConfigurationをセットしていきます。
前回でも貼り付けましたが、見返しやすいようにこちらにも貼り付けています。
Complete the content view
テキストフィールド用のUIContentConfigurationをいよいよセットしていきます。
Conform to the content view protocol
いよいよeditモードに変更すると、タイトル欄のテキストフィールドに該当リマインダーのタイトルが入っているように実装していきます。
- ここまで作成してきたtitleConfigurationを使い、タイトル欄にテキストフィールドをセットします
- やり方は、これまでセクション欄や一覧画面の作成でやってきたcell.contentConfigurationのセットと同じです
Create content views for the date and notes
editモードでもタイトル欄を表示させることが出来たので、同様の実装で日付(date)・注釈(notes)欄も表示できるようにしていきます。
- 日付(date)・注釈(notes)欄の追加の仕方は前セクションと同じです
- ただしまだeditモードで値を編集してDoneボタンを押してもリマインダーの内容は全く更新されません。ここは次回で実装することになります。
文法メモ
UITextView
複数行のテキスト表示・入力をする画面パーツです。
UIDatePicker
日付や時間の選択ができる画面パーツです。
概要についてはこちらのサイトが詳しいです。
今回はiOS13.4から追加されたpreferredDatePickerStyle
を指定し、カレンダーを表示させるように設定しています。どんなスタイルが指定できるかは以下の記事が詳しいです。

Add a working reminder
前回までで編集は出来るようになりましたが、一覧に戻ると編集前の状態に戻されてしまいます。
ここでは編集後の状態で更新されるように実装していきます
Add a working reminder
編集後の状態で更新されるために、現在編集中のリマインダーデータをworkingReminder
という変数に残し、編集前と値が違う場合は更新するように実装していきます。
文法メモ
Equatable
構造体のインスタンスを!=
/ ==
で比較できようになります。
構造体が持つすべてのプロパティの値が一致するかどうか を自動的に比較してくれるようになります。
Make the text configuration editable
文法メモ
UIControl.Event.editingChanged
UITextFieldの値が変更されたことを検知する方法はいくつか存在するのですが、今回は.editingChanged
を使った方法で編集して値が変わったタイミングでonChange
イベントを走らせ、workingReminder
にその値を代入する方法を取っています。
他にも方法はあり、以下の記事が詳しいです。
Make the date configuration editable
前セクションと同様に日付欄も実装していきます。
文法メモ
UIControl.Event.valueChanged
UIDatePickerでは選択し終えたタイミングで変更後の値をセットさせています。
この記事が詳しいです。
Make the notes configuration editable
注釈欄も同様に実装していくのですが、変更後の値のセットが他の2項目と違いDelegate
というやり方で行います。
Delegate
はiOS開発初心者にネックになる箇所の一つです。以下の記事はイラスト混じりのわかりやすい内容になっていて読みやすかったです。
この段階では
- 2つのクラスを跨ぎことが出来る
- UITextViewDelegate を使うと、UITextViewでテキストを編集するときに便利なメソッドを呼んでくる
ということだけを覚えれば十分だと思います。
文法メモ
textViewDidChange:
UITextViewでテキスト編集し終えたタイミングで走らせたいロジックを記載します。
Cancel edits
editモードをキャンセルするcancelボタンを画面左上に追加します。
文法メモ
leftBarButtonItem
ナビゲーションバーの左(=画面左上)に設置するボタンを指定します。閲覧モードのときはnil
に指定してボタンを出さなくする必要があるので注意。
Observe changes in a view hierarchy
最後は編集した内容がリスト一覧に反映されるように実装していきます。
流れとしては
- 既存のupdateReminder(_:)でdata sourceをアップデート
- 既存のupdateSnapshot(reloading:)でsnapshotをアップロード

Adding and deleting reminders
今度はリマインダーの追加と削除が出来るように実装していきます。
Create an add action
まずはリマインダーの追加画面を表示するクリックイベントを追加していきます。
Connect the target-action pair
全セクションで追加したクリックイベントをボタンから実行できるようにしていきます。
Add a new reminder to the model
登録画面は出せるようになりましたが、まだリマインダーでの追加ができません。ここで実際のリマインダーに追加するように修正していきます。
Delete a reminder
今度はリマインダーの削除機能を追加していきます。流れは更新機能と大体同じですが、スワイプを使って削除する必要があるため、それ用の設定が必要となります。
文法メモ
- makeSwipeActions(for:)
- UISwipeActionsConfiguration
- UIContextualAction