オプショナル型

僕はSwiftを勉強し始めていて、いつも通りにコードを書いていると警告が出てきました。
警告にしたがって変数に「!」とか「?」をつけていましたが、具体的な理由は曖昧にしたままコーディングしていました。

とりあえず、「!」をつけておけば値を取り出せる

といった感じで…
しかし、今後のことを考えて、しっかり勉強してみることにしました。
後で自分が見てもわかるようにメモしておきます。

目次

オプショナル型とはなに?

結論から言いますと、
オプショナル型はnilを代入することができるということです。
そのため、Swiftでは基本的にnilを代入できないそうです。

僕は現在、案件の都合でObjective-Cでコードを書くことが多いのですが、時たまnilが原因でアプリが落ちます。
「Dictionary型のオブジェクトにnilを入れてしまう」、「インスタンス化されていないクラスのメソッドを呼ぶ」など。
このように、nilはアプリが落ちる原因になります。
おそらくSwiftはそういう事態を避けるように作られたのでしょう。

しかし、時たまnilを使いたくなる時もあります。
そんなときはオプショナル型を使うことで、今まで通りnilを使ってコードを書くことができます。

ちなみにnilを代入できないオブジェクトを非オプショナル型と言います。

次のセクションではどのようにオプショナル型、非オプショナル型を定義するかを書きます。

オプショナル型で変数(オブジェクト)を定義する

では、オプショナル型と非オプショナル型をどう定義するかを見ていきます。
非オプショナル型は以下のように定義します。
(「?」と「!」がどう違うかはこちらです。)

var(またはlet) [オブジェクト名] : [オブジェクトの型]?

または

var(またはlet) [オブジェクト名] : [オブジェクトの型]!

つまり、型名の後に「?」か「!」をつけることで非オプショナル型のオブジェクトを定義することができます。
例えばこんな感じに。

var text : String!
let number : Int?

これでnilの代入ができるオブジェクトを定義できます。

非オプショナル型で変数(オブジェクト)を定義する

では、オプショナル型と非オプショナル型をどう定義するかを見ていきます。
非オプショナル型は以下のように定義します。

var(またはlet) [オブジェクト名] : [オブジェクトの型]

まあ、言ってしまえばC/C++、C#、Javaなどと同じような感じですね!
具体例を出すならこんな感じです。

var text : String
let number : Int

しかし、非オプショナル型はnilの代入ができない型です。なので、このままではコンパイルエラーが出るため、
定義した時に初期化してあげる必要があります。
こんな感じに。

var text : String = “照橋さんの下の名前は?”
let number : Int = 553

非オプショナル型のオブジェクトの中身を出力する1

先ほどの通り、オプショナル型には「?」と「!」の二種類があります。
オプショナル型の内容を出力する場合、ちょっと特殊な動作が必要になります。
まず、「?」で定義した場合の例です。

import UIKit

class FirstViewController : UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let optional : Int? = 30
        print("\(optional)")
    }
}

結果

Optional(30)

なんか、「Optional」ってものが出ていますね。
このOptionalはいわば包み紙のようなものです。
このままではInt型として使えませんが、以下のように出力するオブジェクトの最後に「!」をつけるとInt型として使えます。他の型についても同様です。

オプショナル型のオブジェクトの中身を出力する2

さきほどは「?」をつけてオプショナル型の定義をしました。
では、今度がもう一つのオプショナル型である「!」を使って定義しましょう。
ちなみにこれは「暗黙的アンラップ」と呼ばれるそうです。

import UIKit

class FirstViewController : UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let optional : Int! = 30
        print("\(10 + optional)")
    }
}

結果

40

つまり、「!」をつけることで「Optional」という包み紙を取って、自動的に中身を使うことができるわけです。
ちなみに、動作確認して見た結果ですが、単に「print(“\(optional)”)」と書いて出力すると「Optional(30)」と表示されました。
どうやら、「!」のオプショナル型単体の使用だとOptionalという包み紙がついて出力されるようです。
なので、今回の例では意図的に10を足すことで、自動的に包み紙の中の30という値を使えることを示しました。

Optional Chaining

Optional Chainingは、オブジェクトがnilかどうか確かめてから、そのオブジェクトの変数やメソッドを呼び出すことです。

例えばこんな感じです。

import UIKit

class FirstViewController : UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let label : UILabel? = UILabel.init(frame: CGRect.init(x: 40, y: 240, width: 200, height: 40))
        label?.text = "これはテストです"
        self.view.addSubview(label!)
    }
}

こんな感じですね。

  • UILabelをオプショナル型で定義する
  • ラベルの文言を編集する
  • ラベルをビューに追加する

ここで、まず「ラベルの文言を編集する」について。
labelのtextという変数を参照するわけですが、labelがnilだと当然見ることはできません。
なので、labelがnilならそれ以降の処理をせずnilを返し、labelがnilでないなら処理を続けるといった感じです。
ちなみに、Optional Chainingしたら、オプショナル型として出力されるため、label?.textを出力すると「Optional」という包み紙がついて出力されます。

余談で先ほどの続きになりますが、ビューに追加するときはオプショナル型からUILabel型に変換してあげる必要があるので、labelの後ろに「!」をつける必要があります。