The Swift Programming Languageのメモ(その7)
はじめに
これは、『The Swift Programming Language』を読んだ時の個人的なメモです。なので、引用はすべて『The Swift Programming Language』から。
iTunes - ブック - Apple Inc.「The Swift Programming Language」
https://itunes.apple.com/jp/book/swift-programming-language/id881256329?mt=11
その6はこちら。
The Swift Programming Languageのメモ(その6) - 開発メモ
http://seeku.hateblo.jp/entry/2014/06/10/194058
Properties
- 値を計算するプロパティはクラス、構造体、列挙型で使えるよ
- 値を格納するプロパティはクラスと構造体で使えるよ
プロパティはインスタンスに持たせるだけじゃなくて、型に持たせることも出来るよ
メモ: C++で言うところのクラス変数みたいなものかプロパティの変更を監視することも出来るよ
プロパティの監視は、値を格納するプロパティで使えるよ。
継承先のクラスで、元のクラスの値を監視することも出来るよ。
メモ: 要確認
Lazy Stored Properties
- 遅延評価プロパティは、最初に使われるタイミングで値を計算することになるよ
- プロパティの属性に『lazy』を指定すると、遅延評価プロパティになるよ
class DataManager { lazy var importer = DataImporter() var data = String[]() // the DataManager class would provide data management functionality here }
Stored Properties and Instance Variables
- Objective-Cの場合、プロパティの裏で使われてるインスタンス変数を直接使うことも出来たよ
- Swiftではそんな事は出来ないよ
メモ: 結果的に、プロパティを監視する仕組みが必要になったと
Computed Properties
- 値を計算するプロパティもあるよ
- これは、値を取得するためのgetterを持つよ
- 必要なら、値を設定するためのsetterも作れるよ
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) } } }
メモ: インデントはこれでいいの?
Shorthand Setter Declaration
- setterの引数を省略すると、自動で『newValue』って名前の変数が使われるよ
Read-Only Computed Properties
- setterを省略すると、読み込み専用のプロパティになるよ
- この場合、getと『{}』が省略できるよ
struct Cuboid { var width = 0.0, height = 0.0, depth = 0.0 var volume: Double { return width * height * depth } }
Property Observers
- プロパティの変更を監視することも出来るよ
プロパティの監視は、値が設定されるたびに呼び出されるよ
すでに同じ値が設定されてても呼び出されるよ。継承先で元のクラスの値を監視することも出来るよ
この場合、値を計算するプロパティも監視できるよ
メモ: 要確認プロパティを監視するには、次の2つの方法があるよ
- willSetは値が変更される直前に呼び出されるよ
- didSetは値が変更された直後に呼び出されるよ
willSetは新しい値、didSetは古い値を参照できるよ
それぞれ、省略すると『newValue』と『oldValue』って名前になるよ。NOTE: willSetとdidSetは、最初の初期化では呼ばれないよ。イニシャライザーの外で値が変更された時だけ、呼び出されるよ
メモ: 要確認
Global and Local Variables
- プロパティは、グローバル変数やローカル変数でも同じように使えるよ
- もちろん、値を計算するプロパティも使えるよ
プロパティの監視も同じように使えるよ
NOTE: グローバル変数は常に遅延評価されるよ。『lazy』を付ける必要はないよ。ローカル変数は遅延評価にできないよ
メモ: C++のグローバル変数の逆? 要確認
Type Properties
インスタンスがプロパティを持つのと同じように、型にもプロパティを持たせることが出来るよ
これを型プロパティって言うよ。
メモ: C++で言うところのクラス変数みたいなものか構造体と列挙型は、型プロパティに値を格納するプロパティも計算するプロパティも使えるよ
クラスでは、型プロパティに計算するプロパティしか使えないよ
メモ: 要確認型プロパティで値を格納するプロパティを使う時は、デフォルト値が必要だよ
型にはイニシャライザーが無いからね。
Type Property Syntax
- Swiftでは、型プロパティは型を定義するときにその中に書くよ
- 構造体と列挙型は『static』を、クラスでは『class』を変数の前にかけば、型プロパティになるよ
struct SomeStructure { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { // return an Int value here } } enum SomeEnumeration { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { // return an Int value here } } class SomeClass { class var computedTypeProperty: Int { // return an Int value here } }
Methods
- メソッドは型に関連付けられた関数だよ
- クラス、構造体、列挙型はインスタンスメソッドを持てるよ
- 同じように、型メソッドも持てるよ
Instance Methods
Local and External Parameter Names for Methods
- 普通の関数は、引数として関数の中で使う名前と外で使う名前を指定することが出来るよ
- メソッドでも同じようなことが言えるけど、デフォルトの動作がちょっと(?)違うよ
- メソッドの場合、最初の引数名はメソッドの中で使う名前になるよ
- 2個目以降の引数名は、同じ名前がメソッドの中と外で使われるよ
メモ: 誰が、こんなに気持ち悪い仕様を考えたの?
- 具体的にはこんな感じになるよ
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes: Int) { count += amount * numberOfTimes } }
- この場合、incrementByの『amount』はメソッドの中だけ。『numberOfTimes』はメソッドの中と外で使われるよ
- このメソッドを呼ぶ時は、こんな感じになるよ
let counter = Counter() counter.incrementBy(5, numberOfTimes: 3) // counter value is now 15
メモ: どうして、こんなに気持ち悪い仕様になってるの?
// both a local counter.increment(5, 3) // both a local and an external name counter.increment(amount: 5, numberOfTimes: 3)
メモ: こっちの方がずっと自然でわかりやすいと思うんだが・・・
Modifying External Parameter Name Behavior for Methods
- メソッドの2個目以降の引数で外で使われる名前が不要な場合、外部引数名として『_』を書いておけば良いよ
The self Property
- すべてのインスタンスで、自分自身を示すプロパティとして『self』が使えるよ
- Swiftはプロパティやメソッドを使う場合、自分自身の物だと仮定してくれるから、いちいち『self』を書く必要はないよ
- 仮定がうまく働かない場合は、明示的に『self』を使えば良いよ
Modifying Value Types from Within Instance Methods
- 構造体と列挙型は、デフォルトではインスタンスメソッドから値を変更できないよ
- 値を変更する必要がある時は、そのメソッドの前に『mutating』ってつければ良いよ
- これで、メソッドからプロパティを自由に変更できるようになるよ
- 新しいインスタンスを生成して、置き換えることも出来るよ
Assigning to self Within a Mutating Method
- 変更可能メソッドは、新しいインスタンスをselfに設定することも出来るよ
struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { self = Point(x: x + deltaX, y: y + deltaY) } }
メモ: 関数のinout引数でこれが呼ばれても大丈夫なのか? 要確認
Type Methods
- 型にメソッドを持たせることも出来るよ
- 構造体と列挙型は『static』を、クラスでは『class』をメソッドの前にかけば、型メソッドになるよ
Subscripts
- クラスや構造体、列挙型は添字でのアクセスを定義できるよ
- 添字アクセスはメンバーやコレクションの要素へのショートカットに出来るよ
- 配列の場合は『someArray[index]』で辞書の場合は『someDictionary[key]』って感じで使われてるよ
Subscript Syntax
- 添字アクセスを定義する時は、引数や戻り値の前に『subscript』を付けるよ
- 具体的にはこんな感じになるよ
subscript(index: Int) -> Int { get { // return an appropriate subscript value here } set(newValue) { // perform a suitable setting action here } }
- setの引数を省略すると『newValue』になるよ
- 読み取り専用ならいろいろ省略できたりするよ
Subscript Options
添字アクセスは複数の引数を取ることが出来るよ
複数の値を渡す時は、『,』で区切るよ引数や戻り値にはどんな型でも使えるよ
- 可変引数も使えるよ
- けど、参照型(inout)やデフォルト値は使えないよ
Inheritance
- クラスは他のクラスを継承して、派生させることが出来るよ
- Swiftは、オーバーライドが正常に行われるようにチェックするよ
- クラスはプロパティの監視を追加することが出来るよ
元々のプロパティが、値を格納するタイプでも計算するタイプでも大丈夫だよ。
Defining a Base Class
- イニシャライザーでは、すべてのプロパティを初期化する必要があるよ
Subclassing
- あるクラスを派生させる場合、こんな感じになるよ
class SomeClass: SomeSuperclass { // class definition goes here }
Overriding
派生先のクラスでは、元のクラスのインスタンスメソッドやクラスメソッドやプロパティや添字アクセスとかをカスタム出来るよ
いわゆるオーバーライドってやつだよ。オーバーライドする時は、『override』を付ける必要があるよ
これがないと、コンパイルエラーになるよ。
Accessing Superclass Methods, Properties, and Subscripts
- 元のクラスの要素にアクセスする時は『super』を使うよ
Overriding Properties
- インスタンスのプロパティや型プロパティをオーバーライド出来るよ
- オーバーライドして、getterやsetterをカスタマイズしたり、プロパティの監視を追加したり出来るよ
Overriding Property Getters and Setters
- 名前と型さえはっきりしてれば、どんなプロパティでもオーバーライド出来るよ
- 読み取り専用のプロパティを読み書きできるようにオーバーライド出来るよ
- けど、逆はできないよ
Preventing Overrides
- 『final』属性をつけると、オーバーライド出来なくなるよ
- varとかfuncとかclassとか、定義するキーワードの前に付けるよ
とりあえずここまで。
(2014/06/11 作成)
(2014/09/25 修正)