はじめに
FY23新卒の副山です。現在、NX開発推進部 iOSアプリ開発グループに所属しています。 カメラと映画鑑賞が好きです。(ポップコーンはキャラメル派です) おすすめの映画は「そして、バトンは渡された」と「今夜、世界からこの恋が消えても」です。 大切なものを考え直すきっかけになる作品ですのでぜひ見てみてください。
さて私は現在、音楽プレイヤーのモックアプリを作成するというOJT課題を行っています。 課題でInterface Builderで作成したUIをコードで置き換えるリファクタリングを行いました。 本記事は以下の2点について具体例を用いて解説します。
- Interface Builderとコードの差分について
- UIをコードで作成するときの注意点
Interface Builderとコードの違いについて
Interface Builderおよびコードで作成できる全てのUI部品はデフォルト値を持っています。 はじめに、Interface Builderとコードで作成した際の違いについて3つの具体例を用いて説明します。
UILabelの違いについて
1つ目はUILabelの違いについて説明します。 UILabelをInterface Builderで作成すると下記のようになります。

Interface BuilderでUILabelを作成すると、 UILabelにはデフォルトで下記のようなプロパティが設定されます。 “Label”という文字がデフォルトで表示されるのは、XcodeのAttributes inspectorエリア上にあるtextプロパティから確認できます。

次に、UILabelをコードで作成する場合について説明します。 下記のようにUILabelを作成できます。
let label = UILabel()
コードで作成したUILabelを
addSubView(label)して画面上に表示します。
しかし、ビルドして確認すると画面上にUILabelが表示されません。
これは、コードでUILabelを作成する場合、”Label”という文字がデフォルトでnilになっていることが原因です。
この問題を解決するためには、コードを下記のように修正すると、Interface Builderのときと同様に”Label”という文字が表示されることを確認できます。
let label = UILabel()
label.text = "Label"
よって、Interface Builderとコードではデフォルトで設定されるプロパティに違いがあることを確認できました。
UIStackViewの違いについて
2つ目は、UIStackViewの違いについて説明します。 UIStackViewをInterface Builderで作成するためには、以下の画像のように2つの横に並んだUILabelを選択し、右端のEmbed Inボタンを押下しStack Viewを選択します。

すると画像のように2つのUILabelがUIStackViewの中に横並びに埋め込まれます。

UIStackViewのプロパティを確認するとaxisがHorizontal(水平)になっています。

今度は、2つの縦に並んだUILabelを選択し、右端のEmbed Inボタンを押下しStack Viewを選択します。

すると画像のように2つのUILabelがUIStackViewの中に縦並びに埋め込まれます。

UIStackViewのプロパティを確認するとaxisがVertical(垂直)になっています。

したがって、Interface BuilderでUIStackViewにUI部品を埋め込むとき、下記の特徴があります。
- 現在のUI部品のレイアウトに近い形のプロパティが自動でデフォルト設定される
- UIStackView内のUI部品を並べる向きを決定するaxisを自動で設定
- UI部品間のスペースを設定するSpacingプロパティを自動で設定
他にもInterface BuilderでUIStackViewを作成する方法があります。 ショートカット(コマンド+Shift+L)または、Xcodeの右上にある+ボタンから下記画面を開きます。

この画面でHorizontal StackViewとVertical StackViewを選択でき、ダブルクリックまたはドラッグアンドドロップすると空のUIStackViewが作成されます。 空のUIStackViewにUI部品をドラッグアンドドロップすると、UIStackView内に埋め込むことができます。
次にコードでUIStackViewを作成する場合について説明します。 下記のように2つのUILabelを定義しUIStackViewに埋め込みます。
let label1 = UILabel()
label1.text = "Label1"
let label2 = UILabel()
label2.text = "Label2"
lazy var stackView = UIStackView(arrangedSubviews: [label1, label2])
ビルドして確認すると下記のようにUIStackView内の2つのUILabelはHorizontal(水平)方向に並んでいることが確認できます。

すなわち、コードでUIStackViewを作成する場合はaxisプロパティはHorizontalにデフォルトで設定されることがわかります。 axisをVerticalに設定したい場合は下記のように明記する必要があります。
lazy var stackView = UIStackView(arrangedSubviews: [label1, label2])
stackView.axis = .vertical
UIStackViewのプロパティ設定について1つ注意点があります。 UIStackViewのaxisをHorizontalに設定したいとき、デフォルトのプロパティとして設定を省略することは可能です。 しかしその場合、コードの可読性が損なわれる可能性があります。 そのため、変更の予定がなくてもプロパティを明示的に記述する方が良い場合があることを念頭に置いておきましょう。
UITextFieldの違いについて
3つ目は実際に私が躓いたUITextFieldの違いについて説明します。 Interface BuilderでUITextFieldを作成すると下記のようになります。

Interface Builderの場合
borderStyle = .roundedRect がデフォルトで設定されるためUITextFieldの枠線が表示されます。
一方コードの場合、
borderStyle = .none がデフォルトで設定されるため、枠線が表示されません。
したがって、枠線を表示するには
borderStyle = .roundedRect プロパティを下記のように明示的に設定する必要があります。
let textField = UITextField()
textField.borderStyle = .roundedRect // 枠線を表示する
UIをコードで作成するときの注意点
これまで、下記2点について解説しました。
- Interface Builderとコードではデフォルトのプロパティに違いがあること
- コードで同じ見た目のUIにするには初期値の異なるプロパティをコードで設定すると解決できること
最後に、UIをコードで作成するときの注意点について解説します。 1点目は、どこにUI部品を設置したかわかりにくいという点です。 白色のUIViewにUITextFieldを設置するとき枠線が非表示の場合、どこにUITextFieldを設置しているかわからない状態になってしまいます。 したがって、コードでUIを作成するときは、UIViewの背景色を白以外(例えばグレー)に設定すると開発しやすくなると考えます。
2点目は、XcodeやSwiftのバージョンの違いによる変化に気づきにくい点です。 デフォルトで設定されるプロパティはXcodeやSwiftのバージョンによって変更される可能性があることに注意する必要があります。 Interface Builderで作成したUIのプロパティはAttributed inspectorエリアで一覧表示できます。 Interface Builderのデフォルトで設定されるプロパティは、コードで実装するときに記述する必要はありません。 しかし、記述していないプロパティのデフォルト値が変更された場合、Appleのリリースノートで告知はされますが、Gitの差分が出ないため、変更に気づきにくいという問題があります。
まとめ
Interface Builderとコードではデフォルトで設定されるプロパティの差分について3つの具体例を用いて解説しました。 コードでUIを作成するとき以下の2点に注意しましょう。
- 初期値に差がないプロパティは原則省略する
- ただしUIStackViewのaxisのような明示した方が良い場合もある
- バージョンの違いに注意する
- 初期値に差がある場合は初期値の異なるプロパティを忘れず設定する
副山俊輔