当サイトでは筆者が学習で躓いた点について、調査内容と自分なりの解釈・解決策をまとめています。
今回のテーマは「暗黙的に実装されるイニシャライザの利用方法(デフォルトイニシャライザとメンバーワイズイニシャライザ)」についてです。
※本記事は、著者が学習した内容をまとめたものとなります。内容の精査につきましては、執筆時の技術力で可能な限りの注意を払っていますが、万が一誤りがございましたらフォームからご一報いただけると幸いです。
この記事で分かること
- デフォルトイニシャライザの特徴
- メンバーワイズイニシャライザの特徴
- デフォルトイニシャライザとメンバーワイズイニシャライザの違い
自分が躓いた点を中心に、初心者の方に向けて記事を書いています!
環境
この記事は以下のバージョン時点での情報をまとめています。
【XCode】15.3
【Swift】5.10
【iOS】17.4.1
【macOS】Sonoma 14.4.1
おさらい:イニシャライザの役割
まずはイニシャライザについて簡単におさらいをしておきます。
クラスや構造体のストアドプロパティは、インスタンスが生成されるまでに全て初期化されている必要があります。イニシャライザは、この「ストアドプロパティ初期化」の役割を担っています。
暗黙的に定義される2種類のイニシャライザ
Swiftではプロパティの初期化にあたって、暗黙的に定義されるイニシャライザが2種類あります。それがデフォルトイニシャライザとメンバーワイズイニシャライザです。
どちらも「暗黙的に定義される」という点で共通しているため、ごっちゃになってしまわないよう、それぞれの特徴と違いをまとめます。
デフォルトイニシャライザとは
デフォルトイニシャライザは「全てのストアドプロパティが初期値を持っている」かつ「イニシャライザが1つも用意されていない」場合に、暗黙的に準備されるイニシャライザのことです。
この場合下記の例のように、初期化すべきプロパティは存在しないため、デフォルトイニシャライザ自体は特別な処理を行いません。
//ストアドプロパティがデフォルト値を持っており、イニシャライザが定義されていないクラス
class User{
var id = 0
var name = "Taro"
var age = 25
//以下のデフォルトイニシャライザが暗黙的に用意される
//init(){}
}
一方、初期化が必要なプロパティが1つでもある場合には、デフォルトイニシャライザは用意されません。
そのため指定イニシャライザ(designated initializer)を自分で用意しないと、コンパイルエラーとなります。
//変数ageにはデフォルト値が設定されていない
class User{
var id = 0
var name = "Taro"
var age: Int
//デフォルトイニシャライザは用意されない
//以下のような指定イニシャライザを用意しないと、エラーになる
//init(age: Int) {self.age = age}
}
構造体ではエラーにならない・・・?
しかし、同様の型をクラスではなく構造体として定義した場合、指定イニシャライザを用意しなくてもエラーになりません。
//変数ageにはデフォルト値が設定されていない
struct User{
var id = 0
var name = "Taro"
var age: Int
//デフォルトイニシャライザは用意されない
//構造体の場合、指定イニシャライザがなくても、エラーにならない
}
なぜでしょうか?
その理由が、次で説明するメンバーワイズイニシャライザの存在です。
メンバーワイズイニシャライザとは
メンバーワイズイニシャライザは、デフォルトイニシャライザとは異なり、ストアドプロパティがデフォルト値を持っていない場合でも暗黙的に用意されるイニシャライザです。
メンバーワイズイニシャライザはプロパティ名と同一名称の引数を取り、引数として受け取った値を用いて、対応するストアドプロパティの初期化を行います。
//各プロパティにはデフォルト値が設定されていない
struct User{
var id: Int
var name: String
var age: Int
//以下のメンバーワイズイニシャライザが暗黙的に用意される
/*
init(id: Int, name: String, age: Int){
self.id = id
self.name = name
self.age = age
}
*/
}
なお以下の例のように、一部のストアドプロパティにのみデフォルト値が設定されている場合、対応するメンバーワイズイニシャライザの引数にデフォルト引数が渡されます。
//変数idとnameにのみデフォルト値が設定されている
struct User{
var id = 0
var name = "Taro"
var age: Int
//以下のメンバーワイズイニシャライザが暗黙的に用意される
//引数idとnameには、デフォルト引数が設定される
/*
init(id: Int = 0, name: String = "Taro", age: Int){
self.id = id
self.name = name
self.age = age
}
*/
}
ただし、メンバーワイズイニシャライザは、構造体では利用可能ですがクラスでは利用できません。
そのため、同じストアドプロパティを持つ型であっても、クラスと構造体ではエラーの有無に違いが出ます。
//変数ageにデフォルト値が設定されていないクラス
class User{
var id = 0
var name = "Taro"
var age: Int
//ageの初期化が必要なため、デフォルトイニシャライザは用意されない
//型Userはクラスであるため、メンバーワイズイニシャライザは用意されない
//指定イニシャライザが用意されていない
//"Class 'User' has no initializers"のエラーが発生する
}
//変数ageにデフォルト値が設定されていない構造体
struct User{
var id = 0
var name = "Taro"
var age: Int
//ageの初期化が必要なため、デフォルトイニシャライザは用意されない
//指定イニシャライザが用意されていない
//型Userは構造体であるため、メンバーワイズイニシャライザが暗黙的に用意される
//エラーは発生しない
}
まとめ
- 全てのストアドプロパティがデフォルト値を持っている場合
➡️クラス・構造体の両方で、デフォルトイニシャライザが暗黙的に用意される - デフォルト値を持たないストアドプロパティが存在する場合
➡️構造体ではメンバーワイズイニシャライザが暗黙的に用意される。
クラスでは指定イニシャライザを自分で準備する必要がある。
以上、参考になれば嬉しいです!
まだまだ勉強中ですので、間違い等ありましたらフォームよりご連絡くださると助かります????????
コメント