プロパティ

構造体のプロパティ
遅延なプロパティ
計算されちゃうプロパティ
オブザーバー
タイププロパティ

構造体のプロパティ

構造体をつくるときにプロパティの値を決めちゃう例。

struct FixedLengthRange {
	var firstValue: Int
	let length: Int
}

var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
rangeOfThreeItems.firstValue = 6

もちろんlengthは定数なので、上の例だと3から変えることはできない。

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
//rangeOfFourItems.firstValue = 6

letに入れてしまうと、定数な構造体になってしまうので、firstValueが変数であっても上記2行目はエラーになってしまう。
ただし、参照型であるクラスではこのようなことは起きない。

遅延なプロパティ

最初に使われるその時まで値が計算されないプロパティ。@lazyを変数に使えばOK(定数はだめ)。
値が外部のものに依存して定まるような変数とかにもつかうとべんり。

//外部ファイルからデータを読み込むクラス
class DataImporter {
	var fileName = "data.txt"
}

class DataManager {
	@lazy var importer = DataImporter()
	var data = String[]()
}

let manager = DataManager()
manager.data += "Some data"
manager.data += "Some more data"

DataManager内に@lazy var importer~とある。DataImporterのインスタンスが作られるのは、上記でDataManagerのインスタンスが作られるタイミングではなく、importerに実際にアクセスがあった時である。

//data.txt
println(manager.importer.fileName)

計算されちゃうプロパティ

ゲッターとセッターを定めて、計算してから値を保存したり取り出したりするようにできる。

//座標
struct Point {
	var x = 0.0, y = 0.0
}
//幅と高さ
struct Size {
	var width = 0.0, height = 0.0
}

//左下の座標と大きさで定まる長方形
struct Rect {
	var origin = Point()
	var size = Size()
	var center: Point {
	get {
		let centerX = origin.x + (size.width / 2)
		let centerY = origin.y + (size.height / 2)
		return Point(x: centerX, y: centerY)
	}
	set(newCenter) {
		origin.x = newCenter.x - (size.width / 2)
		origin.y = newCenter.y - (size.height / 2)
	}
	}
}

var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)

//square.origin is now at (10.0, 10.0)
println("square.origin is now at (\(square.origin.x), \(square.origin.y))")

ゲッターとセッターのお陰で、var origin(左下の座標)を書き換えなくても、var center(中心の座標)を書きかえれば自動的にoriginが新しい値に変わるというシロモノ。
上の例ではset(newCenter) { ... }とやって、与えられたものをnewCenterで表していたが、省略するとnewValueで表すことになる。

struct AlternativeRect {
	var origin = Point()
	var size = Size()
	var center: Point {
	get {
		let centerX = origin.x + (size.width / 2)
		let centerY = origin.y + (size.height / 2)
		return Point(x: centerX, y: centerY)
	}
	set {
		origin.x = newValue.x - (size.width / 2)
		origin.y = newValue.y - (size.height / 2)
	}
	}
}

セッターなしの読み込み(?)オンリーだとこんな感じ。セッターなしの場合もletは使えないので注意。

struct Cuboid {
	var width = 0.0, height = 0.0, depth = 0.0
	var volume: Double {
	return width * height * depth
	}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)

//the volume of fourByFiveByTwo is 40.0
println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")

体積は縦横奥行で決まるものだからセッターはいらんよね、っていう話。

オブザーバー

willSetを設定すると、その値が保存される直前に実行され、didSetだと直後に実行されるブツを作れる。(初期化時は呼び出されない。)
特に指定がない場合、新しい値はnewValue、古い値はoldValueで表すことになる。

class StepCounter {
	var totalSteps: Int = 0 {
	willSet(newTotalSteps) {
		println("About to set totalSteps to \(newTotalSteps)")
	}
	didSet {
		if totalSteps > oldValue {
			println("Added \(totalSteps - oldValue) steps")
		}
	}
	}
}

let stepCounter = StepCounter()
stepCounter.totalSteps = 200
//About to set totalSteps to 200
//Added 200 steps
stepCounter.totalSteps = 360
//About to set totalSteps to 360
//Added 160 steps
stepCounter.totalSteps = 896
//About to set totalSteps to 896
//Added 536 steps

この例だと、totalStepsに値を保存するような操作がある度に
willSet→totalStepsに値保存→didSet
となっている。

タイププロパティ

これ、ただのstaticなのでわ……

struct SomeStructure {
	static var storedTypeProperty = "Some value."
	static var computedTypeProperty: Int {
		//なんか
	}
}

enum SomeEnumeration {
	static var storedTypeProperty = "Some value."
	static var computedTypeProperty: Int {
		//なんか
	}
}

class SomeClass {
	static var storedTypeProperty = "Some value."
	static var computedTypeProperty: Int {
		//なんか
	}
}

上の例だとcomputedTypePropertyにはゲッターしかないが、セッター・ゲッター両方あってもよい。
んで、上の奴は構造体名or列挙体名orクラス名にドットとプロパティ名をやってやればstaticなやつを読みだせる。

println(SomeClass.computedTypeProperty)

//Some value.
println(SomeStructure.storedTypeProperty)

SomeStructure.storedTypeProperty = "Another value."
//Another value.
println(SomeStructure.storedTypeProperty)

次の例はオーディオの左右2種のチャンネルを表現するための構造体。どちらも0~10の整数値をとる。でもって、それぞれお互いに違う値を取るわけだが、取った値の最大値がmaxInputLevelForAllChannelsに保存される。

struct AudioChannel {
	//オーディオが取れる最大の値
	static let thresholdLevel = 10
	static var maxInputLevelForAllChannels = 0
	var currentLevel: Int = 0 {
	didSet {
		//currentLevelはthresholdLevelを超える値はとれない
		if currentLevel > AudioChannel.thresholdLevel {
			currentLevel = AudioChannel.thresholdLevel
		}
		//左右のオーディオがとった値の最大値を記録していく
		if currentLevel > AudioChannel.maxInputLevelForAllChannels {
			AudioChannel.maxInputLevelForAllChannels = currentLevel
		}
	}
	}
}

というわけで早速オーディオを2つ用意。

var leftChannel = AudioChannel()
var rightChannel = AudioChannel()

leftChannel.currentLevel = 7
//7
println(leftChannel.currentLevel)
//7
println(AudioChannel.maxInputLevelForAllChannels)

この例では10より大きい値を取ることができないので、11を指定するとdidSetのちからにより勝手に10に修正される。

rightChannel.currentLevel = 11
//10
println(rightChannel.currentLevel)
//10
println(AudioChannel.maxInputLevelForAllChannels)

↑ PAGE TOP