1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Swiftのオプショナル型について

Posted at

オプショナル型とは

オプショナル型とはデータ型の一つで、変数の宣言時に使用します。
特徴としては変数にnilの代入を許可することで、逆に非オプショナル型はnilの代入を許可しないことになります。

nilとはデータが無い(変数が空の状態)を表します。

iOSではnilに対して操作するとアプリケーションが落ちてしまうことがあり、そのような問題を解決するためにswiftではnilを基本的には許容しないとのことです。しかし、オプショナル型を使うことでnilを扱うことができるようになります。

オプショナル型の使い方

// オプショナル型
var age: Int? 
var name: String!

// 非オプショナル型
var age: Int 
var name: String

オプショナル型は最後にをつけます。非オプショナル型は最後に何もつけません。
また、一般的にオプショナル型 ( Optional Value ) というとは暗黙的アンラップ型 ( Implicitly Unwrapped Optional )と呼ばれるオプショナル型になります。

非オプショナル型の変数は普通に扱う変数で、nilを扱うことのできるオプショナル型の変数は通常とは扱い方が少し異なります。オプショナル型の変数を通常の変数と同様に扱おうとするとおもわぬエラーが起きるため、オプショナル型の値を通常の値に変換するアンラップという方法が必要になります。

暗黙的アンラップ型

一般的なオプショナル型と違い、使用するとき必ず強制的にアンラップされます。利点として、初期値はないが後から必ず値を入れる保証があるものに使うと効果を発揮します。

なぜアンラップが必要なのか?

まずは、オプショナル型と非オプショナル型の出力結果の違いを見ていきます。

// オプショナル型
var name: String?
name = "Taro"
print(name)  // 出力結果 Optional("Taro")

// 非オプショナル型
var name: String
name = "Taro"
print(name)  // 出力結果 Taro

上記の通り、オプショナル型は Optional("Taro") 、非オプショナル型は Taro と出力されていることから大きな違いがあるとわかります。

また、__「Optional(値)」「値」__は異なるもので、同様には扱うことができません。

var a: Int? = 10 // オプショナル型 
var b: Int = 10 // 非オプショナル型
a + b
/* 
-> a + b はエラーとなる
Value of optional type 'Int?' must be unwrapped to a value of type 'Int'
オプションタイプ「Int?」の値 タイプ「Int」の値にアンラップする必要があります。
*/

結果はエラーとなり実行することができません。
なぜなら、変数aOptional(10)変数b10 という値であるため、Optional(10) + 10は計算することができないということになります。
ここで、オプショナル型の値を通常の値 ( Optiona(10)10 ) に変換するためにアンラップという処理が必要ということになります。

アンラップとは

Optionalは値を包み込むラップのようなイメージで、オプショナル型は値をOptionalというラップで包み込んでいます。そうすると、たとえ中身がない ( nil ) 状態でも包み紙だけは存在するため、扱うことができます。
しかし、この便利な包み紙があるために値はラッピングされ、直接扱うことができません。扱うためにはラップを取り除き、中身の値を取り出さなくてはいけません。この包み紙を取り除き、値を取り出すことをアンラップと言います。

アンラップの種類

1. 強制的アンラップ

そのままの意味になりますが、オプショナル型を強制的にアンラップする方法です。オプショナル型の変数の中にどんな値が入っていても関係なく、その値を取り出します。

var name: String?
name = "Taro"
print(name!)  // 出力結果 Taro

オプショナル型の変数に対して!をつけ強制的アンラップをすると、出力がTaroとなりました。
簡単に扱える強制的アンラップですが、アンラップする対象のオプショナル型の変数の中身がnilだった場合、エラーとなりアプリケーションが落ちてしまうという欠点があります。なので、強制的アンラップをする場合は、必ずラッピングの中身が存在する(nilではない)ことが保証されていなければいけません。

2. オプショナルバインディング

強制的アンラップはオプショナル型の変数を中身の値に関係なくアンラップしました。そのため変数にnilが入ってしまうとアプリケーションが落ちてしまうという問題があり、それを解決するアンラップの方法がオプショナルバインディングです。
オプショナルバインディングの特徴は条件式を用いることで、アンラップする対象のオプショナル型の変数がnilかどうかを判定するためのものです。

if let

  • nilだった場合に行う処理が異なる時に使用します。
  • nilの場合は__Aの処理__、nilではない場合は__Bの処理__をするケースでよく使います。
let name: String? = "Taro"

if let unwrappedName = name {
    //「name」が「nil」ではない場合の処理
    print(unwrappedName)
} else {
    //「name」が「nil」である場合の処理
    print("名前がありません") 
}

// -> 出力結果 Taro

guard let

  • これ以上処理を進めたくない場合に使用します。
  • nilが入っていたらエラーとして扱うケースだった場合などによく使います。
let name: String? = "Taro"

guard let unwrappedName = name else { return }
//「name」が「nil」ではない場合の処理を進める
print(unwrappedName)

// -> 出力結果 Taro

3. オプショナルチェイニング

オプショナルチェイニングもオプショナル型の変数の中身がnilのときに安全にプログラムを実行するための機能です。
オプショナルチェイニングの使い方はオプショナル型の変数のあとにをつけます。

オプショナル型の変数?.メソッド()
オプショナル型の変数?.プロパティ

変数!で強制的にアンラップする場合と、変数?でオプショナルチェイニングを使用する場合で比較してみます。

変数!で強制的にアンラップする場合

var str1: String? = "HELLO"
let str2 = str1!.lowercased() 
print(str2) // 出力結果 hello

結果としてhelloが表示されます。ただし、変数str1nilの場合にはエラーとなり、プログラムが落ちます。

変数?で強制的にアンラップする場合

// 変数str1が「nil」でない場合
var str1: String? = "HELLO"
let str2 = str1?.lowercased() 
print(str2) // 出力結果 Optional("hello")

// 変数str1が「nil」である場合
var str1: String? = nil
let str2 = str1?.lowercased() 
print(str2) // 出力結果 nil

この場合、変数str2の値はオプショナル型になり、出力結果はOptional("hello")と表示されます。また、変数str1nilの場合にもエラーとならず、結果はnilとなります。オプショナルチェイニングの結果はオプショナル型となるため、オプショナルバインディングと組み合わせて使用されます。

オプショナルバインディングと組み合わせた使用

var str1: String? = "HELLO"
if let str2 = str1?.lowercased() {
    print(str2)
} else {
    print("str1はnilです!")
}

// -> 出力結果 hello

??演算子nilであった場合のデフォルト値を設定する

オプショナル型の変数 ?? デフォルト値

??演算子は、左辺のオプショナル型の変数がnilでない場合にはその値を戻し、nilの場合には右辺のデフォルト値を戻します。

var name: String?
let defaultName = "Taro"
let yourName = name ?? defaultName
print(yourName) // 出力結果 Taro

まとめ

オプショナル型についてまとめてみました。私の意見にはなりますが、強制的アンラップはアプリのクラッシュの要因の一つになると思いましたので、基本的には__条件分岐が可能__な if letを用いてアンラップし、エラー処理の場合は__以降の処理が実行されない__guard letを用いてアンラップする考え方で行こうと思いました。

参考

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?