Type Casting
昨日に引き続き https://docs.swift.org/swift-book/LanguageGuide/TypeCasting.html を読む。
- Swiftの型キャストは
is
とas
演算子 - protocolをconformしているかどうかにも使える
- 型検査演算子
is
item is Movie
- 「subclassかどうか」だけど構造体・列挙型でも使える
- ダウンキャスト演算子
as?
とas!
- ダウンキャストは失敗するかもしれないので2つある
- ダウンキャストが成功するのがnot sureなときは
as?
を使え - ダウンキャストが成功するのがsureなときは
as!
を使え - “if let movie = item as? Movie” は、「
item
をMovie
としてアクセスしてみて、うまくいったらmovie
一時変数にオプショナル格納されてる値を入れてよね」と読む Any
には全ての型のインスタンスが入る。タプルや関数も入るAnyObject
に入るのはクラスのインスタンスだけswitch
〜case
で型検査する例case 0 as Int:
case let i as Int:
case let x as Double where x > 0:
case let (x, y) as (Double, Double):
case let f as (String) -> String:
Any
にOptionalを入れるには、明にキャストしないと警告になるlet o:Any = Int("123") as Any
intをdoubleにするようなキャストではない
Error Handling
昨日に引き続き https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html を読む。
- Swiftでは、エラーは、
Error
プロトコルに準拠した型の値として表される - Swiftの列挙型はエラー状態に関連したグループをモデル化するのに特に適している
- Swiftではエラーハンドルの方法は4つある
- エラーを伝播させる
-
do
〜catch
構文でハンドリング - オプショナル値として
- エラーは起きないものとして
- Swiftのエラーハンドリングはコールスタックの巻き戻しはしない
throw
文の性能特性は、return
文のと同じくらい
- エラーを投げれば関数はエラーを伝播できる
- エラーを投げない関数の内側では、エラーをハンドリングしなければならない
guard
ステートメントでメソッドを早く抜ける- エラーを投げる関数を呼ぶには
try
キーワードを前につけて do
節でエラーが投げられるかもしれない関数を呼んで、catch
節でどのエラーに対するか決定するcatch
のパターンはcase
みたいな感じで- 最後の
catch
節ではエラーはローカル変数error
に束縛される - 列挙型でキャッチ
catch is VendingMachineError
try?
式でオプショナル値に変換let x = try? someThrowingFunction()
try!
式で、エラーは起きないものという実行時 assertionにしてしまうlet image = try! loadImage(〜)
defer
で現在のスコープが終わるまで実行を後回しする- deferred文では、ステートメント外へ制御を移す
berak
やreturn
やthrow
はできない - 同一スコープで複数
defer
を書いたら、ソースコード順で後のやつから順に呼び出される - エラー処理じゃなくても
defer
構文は使える
最近Web上のSwiftの記事なんかを見て 「読める…読めるぞ!」という雰囲気になってきたので 学習高原に達した気がする。
Optional Chaining
昨日に引き続き https://docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html を読む。
- 強制アンラッピングの代替としてのオプショナル連鎖
- オプショナル値の後に
?
をつけて - オプショナル値が
nil
のとき、オプショナル連鎖は優雅に失敗する、 強制アンラッピングはランタイムエラー - プロパティ等の返り値が非オプショナルであっても、オプショナル連鎖の返り値はいつもオプショナル
- オプショナル連鎖経由で非オプショナルのプロパティを読み取り成功したことは オプショナル束縛で判る
if let x = o.property?.subProperty {
- オプショナル連鎖経由で
Void
のメソッドはVoid?
を返す- 呼んだかどうか検査するには
if o.property?.method() != nil
- プロパティ値設定も同じ
if (o.property?.subProperty = value) != nil
- 呼んだかどうか検査するには
- 添字形式は
a?[x]
table[i]?[j]
- オプショナル値を返すメソッドが混ざっても
if let x = o.p1?.p2?.m1()?.m2()
「オプショナル値の後ろに?
」 であって「?.
演算子ではない」、という解釈
Deinitialization
今日のは少ない
昨日に引き続き https://docs.swift.org/swift-book/LanguageGuide/Deinitialization.html を読む。
- Swiftのメモリ管理はARC
- deinitializer はクラスのインスタンスがメモリから解除される直前に呼び出される
deinit
キーワードをつかってinit
みたいに、 パラメータも括弧()
もなしdeinit {〜}
- ひとつのクラスに最大でひとつの deinitializer
- インスタンスの割り当て解除が行われる直前に、自動的にdeinitializerが呼び出される
- deinitializer の実装はインスタンスのプロパティ全てにアクセスできる
- あなたは自分自身でdeinitializerを呼び出すことはできません
- スーパークラスdeinitializerはサブクラスによって継承される
- サブクラスdeinitializer→スーパークラスdeinitializerの順に呼び出される
- スーパークラスdeinitializerはサブクラスが独自のdeinitializerを提供しない場合でも常に呼び出される
- クラスのインスタンスが入ったOptionalな変数に
nil
を代入すれば deinitializer が呼び出される
LANGUAGE GUIDEの半分は過ぎたみたい
Initialization
訳はてきとう
前回に引き続き https://docs.swift.org/swift-book/LanguageGuide/Initialization.html を読む。
- 格納型プロパティは、初期化子のなかで値を設定するか、プロパティの宣言に初期値を書く
- 初期化子の中で値を設定するか、初期値を宣言したときは、プロパティオブザーバは呼び出されない
- プロパティがいつも同じ初期値をとるなら、初期化子内で設定するよりも初期値を与えよ
- クラスの格納型プロパティにすべて初期値があればデフォルト初期化子がある
- 構造体には全項目初期化子がある
- 初期化子の委譲は
self.init
- 指定初期化子と便利初期化子
- クラスの指定初期化子は、少ない傾向。ひとつしか持たないことがよくある
- どのクラスも1つは指定初期化子を持たなければならない
- 便利初期化子
convenience
修飾子をinit
キーワードの前につけて - 委譲のルール
- 指定初期化子は、スーパークラスの指定初期化子を呼び出さなければならない
- 便利初期化子は、同じクラスの他の初期化子を呼び出さなければならない
- 便利初期化子は、最終的には指定初期化子を呼び出さなければならない
- 単純版
- 指定初期化子は上へ委譲する
- 便利初期化子は横へ委譲する
- Swiftでは、クラスの初期化は2段階
- 2段階初期化プロセスを使用すると、クラス階層内の各クラスに完全な柔軟性を与えながら、初期化を安全に行うことができる
- 2段階初期化は、プロパティ値が初期化される前にアクセスされるのを防ぎ、予期せず別の初期化子によってプロパティ値が別の値に設定されるのを防ぐ
- 安全性検査
- 2つの段階
- 第1段階
- 第2段階
- 継承チェインの先頭から戻りながら、指定初期化子にはさらにカスタマイズする選択肢がある
- 初期化子は、この段階では、
self
にアクセスしたりプロパティ値を変更したり、メソッドを呼んだりできる - 最後に、便利初期化子にはカスタマイズする選択肢がある
- Objective-Cのサブクラスとは異なり、Swiftサブクラスはデフォルトでスーパークラス初期化子を継承しない
- 自動的に継承される初期化子。サブクラスで提供するプロパティにすべて初期値が宣言されているとして、
- 失敗可能初期化子
init?
- 失敗時は
nil
をreturn
するけど、成功時はとくになにもreturn
しないよ - 同じ名前と型のパラメータで失敗可能・失敗不能初期化子を両方定義することはできない
rawValue
のあるenum
は自動的にinit?(rawValue:)
を収容している- 失敗可能を失敗不能にオーバーライドできるけど、逆は無理
- 初期化中に強制アンラップしている失敗可能な初期化子は
init!
- サブクラスで実装しなければならない初期化子は
required init()
- クロージャでプロパティの初期化
let someProperty: SomeType = { return someValue }()
やたら量が多いので、他の章の5倍はあるけど、内容はまあ、ゾッともゲッともしない。ああそうだね、という感じ。 スーパークラスの初期化が終わってないのにスーパークラスのメソッドが呼び出せたりするような危険な状況を回避するために、 厳格で単純なルールを作っている、…と思った(夏休みの感想)。
Inheritance
前回に引き続き https://docs.swift.org/swift-book/LanguageGuide/Inheritance.html を読む。
- 何からも継承してないクラスはベースクラス
- Swiftのクラスはユニバーサル基底クラスからの継承ってのは無い
- クラスメソッド、インスタンスメソッド、クラスプロパティ、インスタンスプロパティ、添字はオーバーライドできる
static func
とstatic var
はオーバーライドできない
- オーバーライドする側で
override
キーワードをつける…誤ってオーバーライドすると予期しない振る舞いをするから - サブクラスでオーバーライドした実装中でスーパークラス版にアクセスするには
super
prefixをつけるsuper.someMethod()
,super.someProperty
,super[someIndex]
- オーバーライドするプロパティの名前と型の両方を常に記述する必要がある
- スーパークラスで読み取り専用だったプロパティを、サブクラスで読み書き可能にできる
- スーパークラスで読み書き可能だったプロパティを、サブクラスで読み取り専用にはできない=>コンパイルエラー
- プロパティをオーバーライドしてsetterを提供するときは、getterも提供しなきゃいけない
- プロパティをオーバーライドして、オブザーバーを追加できる
- willSet(sub)→willSet(super)→didSet(super)→didSet(sub) の順に呼ばれる様子
- 定数格納型プロパティ、読み取り専用計算型プロパティは、オブザーバーを追加できない
- 同じプロパティに対して、オーバーライドセッターとオーバーライドプロパティオブザーバーの両方を指定することはできない
- カスタムセッターの中で値変更を監視すればよい
- オーバーライドを禁止するのは
final
修飾子final var
,final func
,final class func
,final subscript
- サブクラス化を禁止するのは
final class
self
は property で super
は prefix、 final
は modifier、 override
は keyword