プロパティ
ここでは、Swift のクラスや構造体におけるプロパティについて説明します。
説明がくどくなるので、以下「クラスや構造体」 とかかずに「クラス」と書きます。
プロパティについては、クラスも構造体もほぼ同様です。特に違いがある場合は、ここは違う、などと書くようにします。
ストアド・プロパティ
クラス内において、そのクラスの値を保持する変数・定数のことは ストアド・プロパティ (stored properties) といいます。
変数の場合は var で、定数の場合は let で定義します。
定数は初期化後は変更できません。
class Person {
let name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
var p = Person( name: "Hanako", age: 25 )
print( p.name )
print( p.age )
p.age = 30
print( p.age )
// p.name = "Ichiro"
レイジー・ストアド・プロパティ
Swift ではストアドプロパティを、レイジー・ストアド・プロパティとして定義しておけば、プロパティを初めて利用するときに、初期化されるようになります。
これによって無駄なメモリを使わずに済みます。
レイジー・ストアドプロパティを指定するには、lazy 修飾子を指定します。
次の例では、Person オブジェクトの company プロパティにアクセスするまでは、Company クラスが初期化されません。
class Company {
let name: String
init(){
print( "== Company.init ==" )
self.name = "(n/a)"
}
init( _ name: String ){
print( "== Company.init ==" )
self.name = name
}
}
class Person {
let name: String
var age: Int
lazy var company = Company()
init( name: String, age: Int ){
self.name = name
self.age = age
}
}
var p = Person( name:"Hanako", age:25 )
print( p.name )
print( p.age )
print( p.company.name )
実行例
Hanako 25 == Company.init == (n/a)
Person が作成されたタイミングではなく、その中に含む Company にアクセスしたタイミングで初期化されていることがわかりますね。
コンピューテッド・プロパティ
実際に値を保持するのではなく、他のプロパティの値から計算した値をプロパティとすることも出来ます。 これをコンピューテッド・プロパティ (computed properties, 計算プロパティ) といいます。
コンピューテッド・プロパティに値をセットする場合は、次のように set を使います。
class Point {
var x : Double
var y : Double
var x2 : Double {
get {
return x * 2
}
set {
x = newValue/2.0
}
}
init(x: Double, y : Double){
self.x = x
self.y = y
}
}
var p : Point = Point( x: 2.0, y: 3.0 )
print( "p.x = \(p.x) p.y = \(p.y)" )
print( "p.x2 = \(p.x2)" )
p.x2 = 10
print( "p.x = \(p.x) p.y = \(p.y)" )
print( "p.x2 = \(p.x2)" )
実行結果
p.x = 2.0 p.y = 3.0 p.x2 = 4.0 p.x = 5.0 p.y = 3.0 p.x2 = 10.0
set(newX) のように新たに変数を指定することも出来ますが、指定しなければ、set ブロックの中では新しい値は newValue という名前で取得できます。
尚、上記の例であるコンピューテッド・プロパティである x2 を読み取り専用にするばあいは、set ブロックを記述しません。
プロパティ・オブザーバ
プロパティには、プロパティ・オブザーバー (property observers) を設定して、変更が発生するときに処理を行うことができるようになっています。
データベースのトリガーのような感じです。
レイジー・ストアドプロパティには設定できません。
オブザーバは、プロパティ変更前に呼ばれる willSet と、変更後に呼ばれる didSet があります。 willSet では newValue で新しい値が取得でき、didSet では変更前の古い値が取得できます。
class Point {
var x : Double {
willSet {
print("willSet newValue=\(newValue)")
}
didSet {
print("didSet oldValue=\(oldValue)")
}
}
var y : Double
init( x: Double, y: Double ){
self.x = x
self.y = y
}
}
var p : Point = Point( x: 1.0, y: 2.0 )
print( "p.x=\(p.x) p.y=\(p.y)" )
p.x = 3
print( "p.x=\(p.x) p.y=\(p.y)" )
実行結果
p.x=1.0 p.y=2.0 willSet newValue=3.0 didSet oldValue=1.0 p.x=3.0 p.y=2.0