楽水

人々の創造が自由に表現できる舞台づくり

Swift

Swiftのメソッドをわかりやすく解説

投稿日:


メソッドは、特定の型に関連した関数です。
クラス、構造体、列挙型はすべて、型のインスタンスを扱う特定のタスクと機能を持つインスタンスメソッドを定義することができます。
また、クラス、構造体、列挙型は、型自身に関連するタイプメソッドを定義することもできます。
このように、Swiftでは、クラスだけでなく、構造体、列挙型でもメソッドを定義することができます。
今回は、Swiftのメソッドについて以下の観点で解説します。

  • インスタンスメソッド
  • タイプメソッド

参考本
[改訂新版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 WEB+DB PRESS plus

インスタンスメソッド

インスタンスメソッドは、特定のクラス、構造体、あるいは列挙型のインスタンスに属する関数です。
インスタンスプロパティにアクセスまたは変更する手段として、あるいはインスタンスの目的に関連した機能として、インスタンスの機能をサポートします。
インスタンスメソッドは、関数とまったく同じシンタックスです。
次の例では、アクションが起きた回数を数える、シンプルなCounter クラスを定義しています。

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

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

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

selfプロパティ

型のすべてのインスタンスには、インスタンスそのものを示すselfプロパティがあります。
selfプロパティは、自身のインスタンスメソッド内で現在のインスタンスを参照するときに使います。
上の例での increment() メソッドを次のように記述できます。

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

実際には、コードにそれほどselfを記述する必要はありません。
self を明示的に記述しない場合、メソッド内で既知のプロパティ名またはメソッド名を使っている場合には、Swift は現在のインスタンスのプロパティまたはメソッドを参照しているものと想定します。
インスタンスメソッドのパラメータ名と、そのインスタンスのプロパティ名が同じ名前のとき、self プロパティを使ってパラメータ名とプロパティ名を区別します。
次の例は、メソッドパラメータの x とインスタンスプロパティの x を、self で区別しています。

struct Point {
 var x = 0.0, y = 0.0
 func isToTheRightOfX(x: Double) -> Bool {
  return self.x > x
 }
}

インスタンスメソッド内から値型のプロパティを変更する方法

構造体と列挙型は値型です。
デフォルトでは、値型のプロパティをそのインスタンスメソッド内から変更することはできません。
特定のメソッド内で構造体や列挙型のプロパティを変更する必要がある場合、以下の例のうように、メソッドの 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)” と出力

値型のインスタンスを定数とした場合、以下の例のように、プロパティの値も変更することはできません。

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

また、以下の例のように、メソッドは self プロパティにまったく新たなインスタンスを代入することもでき、この新しいインスタンスはメソッド終了時に既存のインスタンスを置き換えます。

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 メソッドは、以下の例のように、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 つの異なる電源の状態 (Off, Low, High) を循環します。

タイプメソッド

Swiftでは型自体で呼び出せるタイプメソッドを定義することもできます。
タイプメソッドの場合、メソッドの func キーワードの前に static キーワードを記述します。
また、以下の例のように、クラスでは、メソッドのスーパークラスでの実装を、サブクラスでオーバーライドすることを許可する class キーワードを使うこともできます。

class SomeClass {
 class func someTypeMethod() {
  // タイプメソッドの実装
 }
}

タイプメソッドは、以下の例のように、型に対するドットシンタックスで呼び出します。

SomeClass.someTypeMethod()

以下は、すべてのインスタンスで共有するタイププロパティhighestUnlockedLevelとタイプメソッドunlockLevelを定義し、個々のインスタンスが管理するインスタンスのプロパティcurrentLevel とインスタンスメソッドadvanceToLevelを定義した例です。

struct LevelTracker {
 static var highestUnlockedLevel = 1
 static func unlockLevel(level: Int) {
  if level > highestUnlockedLevel { highestUnlockedLevel = level }
 }
 static func levelIsUnlocked(level: Int) -> Bool {
  return level <= highestUnlockedLevel
 }
 var currentLevel = 1
 mutating func advanceToLevel(level: Int) -> Bool {
  if LevelTracker.levelIsUnlocked(level) {
   currentLevel = level
   return true
  } else {
   return false
  }
 }
}

今回は、Swiftのメソッドについて解説しました。

-Swift
-,

執筆者: