A Swift Tourその3– Objects and Classes
Swiftの言語仕様である「The Swift Programming Language」に沿って、学んでいきます。
Objects and Classes / オブジェクトとクラス
クラスはクラス名に class をつけて定義します。
Objective−Cに比べてすごくシンプルでいいです。
クラスのプロパティは普通に変数や定数として定義すればいいです。メソッドや関数も同じです。
class Shape { var numberOfSides = 0 func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
インスタンス化はクラス名の後に小かっこ、インスタンスの後にドット(.)をつけてプロパティやメソッドを呼び出せます。
他の言語では当たり前ですが、Objective−Cはここがとっつきにくかったので、すごく敷居が下がっています。
var shape = Shape() shape.numberOfSides = 7 var shapeDescription = shape.simpleDescription()
イニシャライザは init です。
class NamedShape { var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
インスタンス自身のプロパティにアクセスするには self を使っています。
デイニシャライザは deinit です。
サブクラスはクラス名の後に : をつけてその後にスーパークラスを書きます。
標準ルートクラス (Objective−CでいうところのNSObjectだけど名前はないようです)のサブクラスにはスーパークラスは不要です。
スーパークラスのメソッドをオーバーライドしたい場合は override をつけます。つけ忘れたらコンパイラがエラーを出してくれます。
class Square: NamedShape { var sideLength: Double init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 4 } func area() -> Double { return sideLength * sideLength } override func simpleDescription() -> String { return "A square with sides of length \(sideLength)." } } let test = Square(sideLength: 5.2, name: "my test square") test.area() // 27.04 test.simpleDescription() // "A square with sides of length 5.2."
プロパティは値を保持するだけでなく、ゲッター/セッターを使ってアクセスできます。
プロパティはObjective-Cにもあった概念ですが、書き方は C# のプロパティのように分かりやすくなっています。
class EquilateralTriangle: NamedShape { var sideLength: Double = 0.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.sideLength // 3.3
perimeter のセッターとして代入式を使用していますが、セッターの後に小かっこをつかってもいいです。
つまり、下の2行は同じです。
triangle.perimeter = 9.9 triangle.perimeter(9.9)
プロパティの値には変更はないが、セッターの前後に何かの処理をしたい場合は、willSet と didSet をつかいます。
class TriangleAndSquare { var triangle: EquilateralTriangle { willSet { square.sideLength = newValue.sideLength } } var square: Square { willSet { triangle.sideLength = newValue.sideLength } } init(size: Double, name: String) { square = Square(sideLength: size, name: name) triangle = EquilateralTriangle(sideLength: size, name: name) } } var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape") triangleAndSquare.square.sideLength // 10.0 triangleAndSquare.triangle.sideLength // 10.0 triangleAndSquare.square = Square(sideLength: 50, name: "larger square") triangleAndSquare.triangle.sideLength // 50.0
クラスのメソッドと関数には決定的な違いがあります。
関数の引数名は関数内でのみ使い、関数呼び出しのときには使わなくてもいいです。
しかし、メッソッドの引数名はメソッドを呼び出すときにも使う必要があります。
呼び出すときに使うパラメータの名前を外部名というのですが、デフォルトでは外部名はパラメータ名と同じです。
2番目以降の引数には外部名の指定が必須ですが、外部名に – を使えば外部名を無効にして関数と同じように呼び出すことができます。
Objective-Cと同じ作法ですが、互換性を考慮したのでしょうか。分かりにくさが残ってしまっています。
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes times: Int) { count += amount * times } } var counter = Counter() counter.incrementBy(2, numberOfTimes: 7) // 2番目以降の引数には外部名の指定が必要
インスタンスをoptional valueとして扱うこともできます。
インスタンスがoptional valueであるとき、メソッドやプロパティを呼び出す前に ? をつけることで、おのインスタンスが nil だったら、それ以降は無視して、nil を返します。
nil でなければ、その後の処理が実行されます。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare?.sideLength // optionalSquare は nil でないので nilでない結果が返る
「A Swift Tourその4」に続きます。
「The Swift Programming Language」で使用されているコードはplaygroundとしてダウンロードして、XCodeで開くことができます。
https://developer.apple.com/library/ios/swift_tour