メソッド

インスタンスのメソッド
自分のところのプロパティを指すself
値型のメソッド
自分自身を指すself
タイプメソッド

インスタンスのメソッド

まあふつうのやつ。

class Counter {
	var count = 0
	//countの値を1増やす
	func increment() {
		count++
	}
	//引数の数だけcountの値を増やす
	func incrementBy(amount: Int) {
		count += amount
	}
	//countの値をゼロにする
	func reset() {
		count = 0
	}
}

というわけで、このCounterのインスタンスをcounterに入れて使ってみる。

let counter = Counter()	//0
counter.increment()		//1
counter.incrementBy(5)	//6
counter.reset()			//0

それと、関数の定義と呼び出し | s.terminal-end.netにあるとおり、関数の引数には定義時に使う時のおなまえと、実際に使う時のお名前がある。
原則として、メソッドの1番目の引数はローカルなお名前、2番目以降の引数はローカル兼グローバルな名前となる。
ちがうCounterクラスを用意してみた。

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

1つ目の引数amountはローカルなお名前だが、2つ目(以降)であるnumberOfTimesはローカルなお名前としてもグローバルな名前としても働く。なので、使う時はこんな書き方が出来る。

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

最初の引数の奴がローカルなだけでグローバルとならないのは、「メソッド名からわかるだろ!?」ということらしい。2つ目以降の引数がなんなのかをはっきりさせることで何のメソッドを使っているのかはっきりさせるための仕様ということか。
ふつうの関数ではそのままではローカル兼グローバルとはならないので、このへんメソッドと関数で違うところである。ただ、別にメソッドの引数のとこに#を付けちゃったからといってヤバイことがあるわけではない。

func incrementBy(amount: Int, #numberOfTimes: Int) {
	count += amount * numberOfTimes
}

あと、最初の引数に#を付けるとちゃんとローカルグローバル兼用になるとのこと。あるいは、関数と同様グローバル用のお名前を付けてもよい。
で、2個目以降の引数にグローバルな名前要らねえよ!という場合はグローバルな名前を指定する位置に「_」を書くといいらしい。「_ numberOfTimes: Int」みたいな(多分)

自分のところのプロパティを指すself

自分のクラスのメソッドだよ!と明示する時はselfで。javaとかのthisといっしょ。

func increment() {
	self.count++
}

ありがたみのある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)
//This point is to the right of the line where x == 1.0
if somePoint.isToTheRightOfX(1.0) {
	println("This point is to the right of the line where x == 1.0")
}

値型のメソッド

プロトコル | s.terminal-end.netでもあった通り、値型である構造体や列挙型において、プロパティの値を書きかえるような関数は作ることができない。
もし作りたいならmutatingと書いておく。

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

定数なヤツでmutatingを使うと怒られちゃうので注意。

let fixedPoint = Point(x: 3.0, y: 3.0)
//fixedPoint.moveByX(2.0, y: 3.0)

自分自身を指すself

selfで自分自身を指すことにより、新しくインスタンスを作ってそいつを新しい自分にすえることができる。(何言ってんだコイツ)

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

別に、コイツは前項のmutating func moveByX(deltaX: Double, deltaY: Double)と変わらない。

列挙型での例。オーブンの火力が……→Low→High→Off→Low→High→Off→……とくるくるかわる。

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()	//.High
ovenLight.next()	//.Off

タイプメソッド

static。と思いきや、クラスの場合はstaticと書かない。

class SomeClass {
	class func someTypeMethod() {
		//なんか
	}
}

静的メソッド中のselfは、インスタンスではなく型そのものを指すらしい。(?)

structでの例。こちらはstaticと書く(列挙型も同様)
1人用ゲームの進捗を保存しておく構造体らしい。ただし、1つのデバイス上で複数のプレイヤーのデータを保存するとかいうやつ。
んで、最初はレベル1しか解禁されていないが、複数いるプレイヤーのうちの誰か1人でもクリアすると全員に対し次のレベルが解禁される。

struct LevelTracker {
	//プレイヤー(複数)がどこまで解禁させたか
	static var highestUnlockedLevel = 1
	//新しいレベルが解禁されたときにhighestUnlockedLevelを書き換える
	static func unlockLevel(level: Int) {
		if level > highestUnlockedLevel { highestUnlockedLevel = level }
	}
	//そのレベルが解禁されているかどうかをしらべる
	static func levelIsUnlocked(level: Int) -> Bool {
		return level <= highestUnlockedLevel
	}

	//(各プレイヤーごとの)レベル
	var currentLevel = 1
	//そのレベルが解禁済みであればレベルを書き換え(書き換え可能であるかどうかをboolで表現)。
	mutating func advanceToLevel(level: Int) -> Bool {
		if LevelTracker.levelIsUnlocked(level) {
			currentLevel = level
			return true
		} else {
			return false
		}
	}
}

でもって、Playerクラスを作って使ってみる。

class Player {
	//プレイヤーごとの進捗を保存するためのLevelTrackerのインスタンス
	var tracker = LevelTracker()
	let playerName: String
	//1つレベルをクリアすると、レベルを解禁したり、自分のレベルを1つ上げたりする
	func completedLevel(level: Int) {
		LevelTracker.unlockLevel(level + 1)
		tracker.advanceToLevel(level + 1)
	}
	init(name: String) {
		playerName = name
	}
}
}

var player = Player(name: "Argyrios")
player.completedLevel(1)
//highest unlocked level is now 2
println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")

Argyriosという人が頑張ったおかげでレベル2まで解禁されたが、2までなので、解禁済みでないレベルに書き換えようとすると怒られる。

player = Player(name: "Beto")
//level 6 has not yet been unlocked
if player.tracker.advanceToLevel(6) {
	println("player is now on level 6")
} else {
	println("level 6 has not yet been unlocked")
}

↑ PAGE TOP