インスタンスメソッドは、特定のクラス、構造体、あるいは列挙型のインスタンスに属する関数です。インスタンスプロパティにアクセスまたは変更する手段として、あるいはインスタンスの目的に関連した機能として、インスタンスの機能をサポートします。インスタンスメソッドは、Functions で説明されている関数とまったく同じシンタックスです。

インスタンスメソッドは、属する型の波括弧の開きと閉じの間に記述します。インスタンスメソッドは、その型の他のすべてのインスタンスメソッドとインスタンスプロパティにアクセス可能です。インスタンスメソッドは、属する型のインスタンスでのみ呼び出すことができます。インスタンスなしで単独で呼び出すことはできません。

次の例では、アクションが起きた回数を数える、シンプルな Counter クラスを定義しています。

class Counter {
    var count = 0
    func increment() {
        count += 1
    }
    func incrementBy(amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}

Counter クラスは 3 つのインスタンスメソッドを定義しています。

  • increment は、カウンターを 1 増やします。
  • incrementBy(amount: Int) は、指定した整数だけカウンターを増やします。
  • reset は、カウンターをゼロにリセットします。

Counter クラスは、カウンターの現在値を記録するための変数プロパティ count も宣言しています。

プロパティと同じくドットシンタックスでインスタンスメソッドを呼び出します。

let counter = Counter()
// counter の初期値は 0
counter.increment()
// counter の値は 1
counter.incrementBy(5)
// counter の値は 6
counter.reset()
// counter の値は 0

メソッドのローカルと外部のパラメータ名

関数のパラメータには、Specifying External Parameter Names で説明されているように、(関数の本体内で利用する)ローカル名と(関数を呼び出すときに利用する)外部名があります。メソッドは型に関連付けられている関数であり、メソッドのパラメータにおいても同じです。

Swift でのメソッドは、Objective-C でのそれとよく似ています。Objective-C と同様に、Swift でのメソッドの名前は、Counter クラスの例の incrementBy(_:) メソッドのとおり、with や forby などの前置詞を使ってメソッドの最初のパラメータを参照します。前置詞を使うことで、メソッドを呼び出すときに文章として読みやすくなっています。

Swift では、メソッドの最初のパラメータ名がデフォルトでローカルのパラメータ名で、2 つ目以降のパラメータ名はデフォルトでローカルと外部のパラメータ名となります。この規約は、Objective-C でメソッドを記述する命名と呼び出しの規約に一致し、メソッド呼び出しの表現を豊かにしています。

Counter クラスにより複雑な形式の incrementBy(_:) メソッドを定義する別バージョンを見てみましょう。

class Counter {
    var count: Int = 0
    func incrementBy(amount: Int, numberOfTimes: Int) {
        count += amount * numberOfTimes
    }
}

この incrementBy(_:numberOfTime:) メソッドには 2 つのパラメータ amount と numberOfTimes があります。Swift はデフォルトで、amount をローカル名としてのみ扱いますが、numberOfTimes をローカル名と外部名の両方として扱います。次のようにメソッドを呼び出します。

let counter = Counter()
counter.incrementBy(5, numberOfTimes: 3)
// counter の値は 15

関数名の incrementBy(_:numberOfTimes:) から意図が明確であり、第一引数値に外部パラメータ名を定義する必要はありません。一方で、第二引数にはメソッドの呼び出し時に意図を明確にする外部パラメータ名を定義します。

Swift でのメソッド定義は Objective-C と文法的に同じスタイルで記述され、自然で表現力ある呼び出しとなっています。

メソッドの外部パラメータ名の振る舞いを変更

デフォルトの振る舞いではないものの、メソッドの最初のパラメータに外部パラメータを付けると役立つ場合があります。そうするために、明示的に外部名を追加することができます。

逆に、メソッドの 2 つ目以降のパラメータに外部名を付けたくない場合には、そのパラメータの明示的な外部パラメータ名としてアンダースコア記号 (_) でデフォルトの振る舞いをオーバーライドします。

self プロパティ

型のすべてのインスタンスには、インスタンスそのものに相当する非明示的なプロパティ self があります。自身のインスタンスメソッド内で現在のインスタンスを参照するために self プロパティを利用します。

上の例での increment() メソッドを次のように記述できます。

func increment() {
    self.count += 1
}

実際には、コードにそれほど self を記述する必要はありません。self を明示的に記述しない場合、メソッド内で既知のプロパティ名またはメソッド名を使っている場合には、Swift は現在のインスタンスのプロパティまたはメソッドを参照しているものと想定します。これは、Counter の 3 つのインスタンスメソッド内での(self.count でなく)count の使われ方で確認できます。

この規則の例外は、インスタンスメソッドのパラメータ名と、そのインスタンスのプロパティ名が同じ名前のときに発生します。この状況では、パラメータ名が優先され、プロパティをより限定した方法で参照する必要があります。self プロパティを使ってパラメータ名とプロパティ名を区別します。

次の例は、メソッドパラメータの x とインスタンスプロパティの x を、self で区別しています。

struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOfX(x: Double) -> Bool {
        return self.x > x
    }
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOfX(1.0) {
    print("This point is to the right of the line where x == 1.0")
}
// "This point is to the right of the line where x == 1.0" と出力

self が無い場合、Swift は両方の x が共にメソッドパラメータの x を参照しているとしてしまいます。

インスタンスメソッド内から値型を変更

構造体と列挙型は値型です。デフォルトでは、値型のプロパティをそのインスタンスメソッド内から変更することはできません。

しかし、特定のメソッド内で構造体や列挙型のプロパティを変更する必要がある場合、そのメソッドに mutating の振る舞いを許可することができます。メソッド内からそのプロパティを変更できるようになり、そしてその変更はメソッド終了時に元の構造体に反映されます。メソッドは self プロパティにまったく新たなインスタンスを代入することもでき、この新しいインスタンスはメソッド終了時に既存のインスタンスを置き換えます。

メソッドの func キーワードの前に mutating キーワードを置くことで、この振る舞いを許可することができます。

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveByX(deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// "The point is now at (3.0, 4.0)" と出力

この構造体 Point は、Point インスタンスを移動する mutating な moveByX(_:y:) メソッドを定義しています。新しいポイントを返す代わりに、このメソッドは呼び出された時点でのポイントを実際に変更します。そのプロパティを変更できるようにするために、mutating キーワードが定義に追加されています。

構造体型の定数では、Stored Properties of Constant Structure Instances で説明されているように、プロパティが変数であったとしても、そのプロパティを変更することはできないため、mutating なメソッドを呼び出すことはできません。

let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveByX(2.0, y: 3.0)
// これはエラー

mutating メソッド内で self に代入

mutating メソッドは self プロパティにまったく新たなインスタンスを代入することができます。上で見た Point の例は、次のように書き換えることができます。

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveByX(deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}

mutating な moveByX(_:y:) メソッドのこのバージョンは、x 値と y 値がターゲットの位置に設定された新しい構造体を生成します。このメソッドの別バージョンを呼び出した結果は、前のバージョンを呼び出すのとまったく同じことになります。

列挙型の mutating メソッドは、self パラメータに同じ構造体の別のケースを設定することができます。

enum TriStateSwitch {
    case Off, Low, High
    mutating func next() {
        switch self {
        case Off:
            self = Low
        case Low:
            self = High
        case High:
            self = Off
        }
    }
}
var ovenLight = TriStateSwitch.Low
ovenLight.next()
// ovenLight は .High
ovenLight.next()
// ovenLight は .Off

この例では、状態が 3 つあるスイッチの列挙型を定義しています。next() メソッドが呼び出されるたびに、スイッチは 3 つの異なる電源の状態 (OffLowHigh) を循環します。


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.