The Swift Programming Language 勉強記録 - 3
なんとか第3回目。先が長いですね、困った(´ー`)
とりあえず"A Swift Tour"の終わりまでを目指します。
クラス
クラスを作成するときはこんな感じ。
class NamedShape { // property var numberOfSides: Int = 0 var name: String // initializer:インスタンス作成時に呼ばれる init(name: String) { self.name = name } // deinitializer:ARC(Automatic Reference Counting)によって自動的に呼ばれる deinit { println("deinit") } // method func simpleDescription() -> String { return "\(self.name) shape with \(numberOfSides) sides." } } // インスタンス生成 let namedShape = NamedShape(name: "HOGE") // メソッドコール namedShape.simpleDescription() // "HOGE shape with 0 sides." namedShape.numberOfSides = 9 namedShape.simpleDescription() // "HOGE shape with 9 sides."
initはJavaやC++のコンストラクタのようなもので、インスタンス生成の際に呼ばれ、初期化処理などを記述する。
すべてのプロパティ値は宣言時に初期化するか、init内で代入してやる必要がある。
deinitというのはインスタンスへの参照がなくなったときにARCによって自動的に呼ばれるもので、何かしら後始末したい処理を書いたりする(ARCは自動でメモリ管理を行ってくれる仕組み)。
継承
クラスの継承は次のように行う。
// NamedShapeクラスを継承したCircleクラスを定義 class Circle: NamedShape { var radius: Double init(radius: Double, name: String) { self.radius = radius // 親で定義しているinitを呼び出して親の持っているnameにセット super.init(name: name) } // 面積を求める func area() -> Double { return radius * radius * 3.14 } // 説明を出力(オーバーライド) override func simpleDescription() -> String { return "\(self.name) circle with radius \(self.radius)" } } let testCircle = Circle(radius: 1.2, name: "My circle") testCircle.area() // 4.5216 testCircle.simpleDescription() // "My circle circle with radius 1.2"
Getter と Setter
プロパティに対するゲッター・セッターを次のような形で持たせることができる。
// 正三角形クラス class EquilateralTriangle: NamedShape { var sideLength: Double = 0 init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 3 } // 周囲を求める var perimeter: Double { get { return 3.0 * sideLength } set { sideLength = newValue/3.0 } } override func simpleDescription() -> String { return "An equilateral triangle with sides of length \(sideLength)" } } var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle") triangle.perimeter // 9.3 triangle.perimeter = 9.9 triangle.perimeter // 9.9
perimeterプロパティ宣言時に、ブロックを使ってget{...}とset{...}を持たせてあげた上で、参照や代入を行うとget・set内の処理が走る。
なお、セッターの内部ではnewValueという変数を自動的に持つことになり、プロパティへ代入した値がこの変数に入る。
この変数名はset(foo){...}とすることにより、明示的に指定できる。
// setを以下のように書き換えてもOK set(foo) { sideLength = foo/3.0 }
willSet と didSet
willSetとdidSetについて。
willSetはプロパティに対して値がセットされる前に実行され、didSetは値がセットされた後に実行される。
class Person { var name: String = "" { willSet { println("willSet! name property is \(name)") } didSet { println("didSet! name property is \(name)") } } } let taro = Person() taro.name = "Taro" // この前後でwillSet, didSetが呼ばれる // Console Output // willSet! name property is // didSet! name property is Taro
上の例では、willSetはnameプロパティに値が入る前に呼ばれるので初期値の空のまま出力。
didSetはnameプロパティに値が入った後に呼ばれるので"Taro"が入っている。
メソッドと関数の違い
メソッドと関数には重要な違いがある。
関数の引数名は関数内部でのみ使用され、関数を呼び出すときには使用しない。
一方メソッドはメソッド内部でも、メソッドを呼び出す際にも使用される(ただし、第一引数だけはメソッドを呼び出す際には使用されず、内部のみでの使用)。
class Person { func greet(name: String, age: String, from: String) -> String { return "I am \(name) from \(from). \(age) years old." } } let ken = Person() // 第一引数のみ内部、第二引数以降外部 ken.greet("Ken", age: "10", from: "Japan")
なお、内部で使用する引数名と、呼び出し時に使用する引数名を分けることもできる。
class Person { func greet(name: String, numberOfAge age: String, from: String) -> String { return "I am \(name) from \(from). \(age) years old." } } let ken = Person() // numberOfAgeという外部のパラメータ名をつけた // ageは内部パラメータ名となる ken.greet("Ken", numberOfAge: "10", from: "Japan")
Optional型
optional valuesも使用できる。
使いたい場合は次のように記述する。
var testCircle: Circle? = Circle(radius: 1.2, name: "My circle") testCircle?.area() testCircle?.simpleDescription() testCircle = nil testCircle?.area() // nil
Optional型の変数がnilの場合、その後はプロパティにアクセスしたり、関数を呼び出したりした際にnilを返すようになる。
つづく。