nilが予想される場合、型名の後ろに?
をつけますよね?
オプショナル変数の事ですが、その状態をSwiftではラップされた状態などと表現します。
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Unexpectedly
は「想定外」みたいな意味、unwrapping
はラップされていない変数。
...なので「ラップされていない変数にはnilが来ないはずなのに、想定外にnilが見つかりました」みたいな意味ですね👀
今回のようにnilが想定される値はラップされた変数に入れなくてはいけませんが、それをラップされていない変数(nilを許容しない変数)に変更することを「アンラップ」するといいます。
アンラップの方法はいくつかありますが、!
をつけるのも一つの方法です(強制アンラップとかいいます)。
しかし、!
は100%nilにならない事が証明されている場合にのみ使いましょう。
大げさかもしれませんが、仕事なら「この変数にnilが渡されたらクビでもいい」ぐらいの覚悟でいいかと😅
あとは、「もうこの変数にnilが入るならアプリ自体クラッシュしてほしい」の時ですかね👀
outlet変数なんかには強制アンラップを使っていますよね😊(storyboardで定義したoutletを受け取れないならアプリが成り立つわけ無いですから😅)
おそらくprivate let
と書かれているのでメンバ変数の話でしょうかね👀
色々手段はあるとは思いますが...
AVAudioPlayer?
のまま使う
メリット
- 安全(実行時エラーはほぼ起きないでしょう)
- nilのエラーを処理するタイミング・処理の仕方が自由
デメリット
音を鳴らすためのPlay
メソッドなどを書くときでも、以下みたいにすればnilの時だけ再生されないだけです👀
もちろん例外処理をしてもよいです!
swift
1func Play() {
2 Sound?.<<実行するメソッド>>
3}
イニシャライザでnilチェック
初期化時に絶対Soundがnilで無いことを保証するクラスにしたいならこのパターンかと👀
デメリットも気にするほどのことではないです。
メリット
- 安全
- 初期化時に例外処理(エラー処理)が必要
- 初期化時にnilチェックしているため、クラスの中で使う場合にnilチェックが不要
デメリット
- 「初期化に失敗したが、再生するはずでは無かった」みたいな時もエラーとして扱う。
- このクラスを使う側でエラー処理が必要になるかも(try使うぐらいでしょうが👀)
swift
1private let Sound: AVAudioPlayer
2
3// 投げる例外はテキトーなのであしからず...
4init() throws {
5 guard let data = NSDataAsset(name: "sound") else { throw NSError(); }
6 guard let sound = try? AVAudioPlayer(data: data.data) else { throw NSError(); }
7 Sound = sound
8}
まとめ
他にも色々方法はありますし、手段はたくさんあるでしょうね👀
今回は再生ファイルですし、私ならイニシャライザで全てチェックしておくかな🤔(こればかりは全体を見ないと分かりませんね😅)
まぁ...とはいえ今回はprivate
な変数に対しての話なので、ラップされたまま置いておくのも手だとは思います。エラー処理は基本的に行わずに、nilの時は音を鳴らさないだけ...というような処理もかけますしね😊
「ラップされた変数をいかにアンラップしながら使うか」はたくさんの方法があるので書き切れませんが、そこを覚えてみると案外面倒ではないですよ!上で使っているguard let
、それ以外にもif let
、?.
、??
...いろいろな方法で安全にアンラップする方法はあります😊
swiftより古い言語なんかだとif(変数 != nil) 〜
みたいな処理無茶苦茶書かなくてはいけないですからね〜😭
引数持ちの関数の冒頭なんかはまずこの文から書き始めるぐらいです😅
一般的にはオプショナル変数みたいな機能の事をnull安全といいますが、無茶苦茶便利ですよ〜😊
参考になれば幸いです😊