入力パラメータやオプショナル型プロパティで初期化処理を変更、あるいは初期化の間に定数プロパティに代入して初期化処理を変更することができます。

初期化パラメータ

初期化処理を変更する値の型と名前を定義するために、イニシャライザの定義の一部として初期化パラメータを定義することができます。初期化パラメータの機能やシンタックスは、関数やメソッドのパラメータと同じです。

次の例では、摂氏での温度を保管する構造体 Celsius を定義しています。構造体 Celsius は、異なる温度尺度の値で構造体の新しいインスタンスを初期化する 2 つのイニシャライザ init(fromFahrenheit:) と init(fromKelvin:)を実装しています。

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius は 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius は 0.0

1 つ目のイニシャライザには、外部名が fromFahrenheit で、ローカル名が fahrenheit の初期化パラメータが 1 つあります。2 つ目のイニシャライザには、外部名が fromKelvin で、ローカル名が kelvin の初期化パラメータが 1 つあります。両イニシャライザは、引数を摂氏での値に変換し、temperatureInCelsius プロパティにその値を保管します。

ローカルパラメータ名と外部パラメータ名

関数やメソッドのパラメータと同じく、初期化パラメータはイニシャライザの本体内で利用するローカル名と、イニシャライザを呼び出すときに利用する外部名の両方を持つことができます。

しかし、イニシャライザは関数やメソッドのように丸括弧の前に関数名を持ちません。従って、イニシャライザのパラメータの名前や型が、どのイニシャライザが呼び出されるかを特定するために、特に重要な役割を果たしています。こうしたことから、外部名を定義していない場合に、Swift はイニシャライザにあるすべてのパラメータに自動の外部名を与えます。

次の例では、3 つの定数プロパティ redgreenblue を持つ構造体 Colorを定義しています。これらのプロパティは、赤、緑、青の色を示す 0.0 から 1.0 までの値を保持します。

Color には、赤、緑、青のコンポーネントに、適切に名前が付けられた Double 型のパラメータを持つイニシャライザがあります。また、Color には 3 つのカラーコンポーネントすべてを同じ値にする、white パラメータを持つ 2 つ目のイニシャライザがあります。

struct Color {
    let red, green, blue: Double
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    init(white: Double) {
        red   = white
        green = white
        blue  = white
    }
}

どちらのイニシャライザも、イニシャライザの各パラメータに名前付きで値を渡して、新しい Color インスタンスを生成するために使用することができます。

let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)

外部パラメータ名を使わずに、これらのイニシャライザを呼び出すことはできないことに注目してください。定義されている場合には、イニシャライザで常に外部名を使用する必要があり、省略するとコンパイル時エラーになります。

let veryGreen = Color(0.0, 1.0, 0.0)
// コンパイル時エラー - 外部名が必須

外部名が無いイニシャライザのパラメータ

イニシャライザのパラメータに外部名を使用したくない場合には、デフォルトの振る舞いをオーバーライドするための明示的な外部名の代わりに、そのパラメータにアンダースコア (_) を記述します。

次は前述の Celsius の例を拡張したバージョンで、すでに摂氏である Double値から、新しい Celsius インスタンスを生成するためのイニシャライザを追加しています。

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}
let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius は 37.0

イニシャライザの呼び出し Celsius(37.0) は、外部パラメータ名が必要無いほどに意図が明確です。そのため、このイニシャライザを init(_ celsius: Double) と記述していることは適切で、Double 値に名前を付けずに呼び出すことができています。

オプショナル型プロパティ

型に値が無いことを論理的に許容できるストアドプロパティがある場合、おそらく初期化の間にその値は設定されないか、あるいは後になって値が無い状態になるために、オプショナル型でプロパティを宣言します。オプショナル型のプロパティは、自動的に nil の値で初期化され、初期化の間にはまだ値が無いことを意図しているプロパティであることを示しています。

次の例では、オプショナル String の response プロパティを持つ SurveyQuestion クラスを定義しています。

class SurveyQuestion {
    var text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
// "Do you like cheese?" と出力
cheeseQuestion.response = "Yes, I do like cheese."

調査の質問に対する回答は、尋ねられるまでわかることはないため、responseプロパティは String?(オプショナル String)型で宣言されています。SurveyQuestion の新しいインスタンスが初期化されるときに、文字列がまだ無いことを意味するデフォルト値の nil が自動的に代入されます。

初期化の間に定数プロパティに代入

初期化終了までに値が設定される限り、初期化のどの時点ででも定数プロパティに値を代入することができます。定数プロパティに値を代入すると、その後に変更することはできません。

NOTE
クラスインスタンスでは、初期化の間に定数プロパティをそのクラスでは変更することができます。サブクラスによって変更することはできません。

SurveQuestion のインスタンスが生成された後に質問が変更されることは無いことを示すために、質問の text プロパティを変数プロパティではなく、定数プロパティを使うように SurveyQuestion の例を修正することができます。textプロパティは定数ですが、クラスのイニシャライザ内では設定することができます。

class SurveyQuestion {
    let text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// "How about beets?" と出力
beetsQuestion.response = "I also like beets. (But not with cheese.)"

Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.