OptionalなどSwiftとObjective-Cの違いを意識してPhotos Frameworkを使うiPhone 6/6 Plusアプリ開発入門(4)(2/3 ページ)

» 2015年03月03日 17時40分 公開
[平屋真吾,クラスメソッド株式会社]

Swiftにおけるswitch文

 「checkAuthorizationStatus」メソッド内では、switch文を使用して処理を分岐させています。「Swiftにおけるswitch文」と「C言語やObjective-Cのswitch文」を比較すると、以下のような点が異なっています。

  • case文の最後に「break」を記述する必要がない
  • 整数値だけではなく、文字列や構造体なども扱える
  • case文に指定可能な条件が増えた
  • 値を全て網羅する必要がある

Swiftにおけるif文

 if文についても「Swift」と「C言語やObjective-C」の違いを比較してみます。異なる部分は以下の通りです。

  • 条件式の( )を省略可能
  • 条件式の後の{ }は省略できない
  • 条件式の評価後の値がBool型でなければならない

 次に、フォトライブラリから写真の情報を取得し、写真に付随する位置情報を使ってMapViewにピンを立てます。

フォトライブラリから全ての写真のPHAssetオブジェクトを取得する

 先ほど登場した「prepareAnnotations」メソッドの内容は以下の通りです。

private func prepareAnnotations() {
    let fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: nil)
    fetchResult?.enumerateObjectsUsingBlock ({result, index, stop in
        if let asset = result as? PHAsset {
            if let location = asset.location {
                let annotation = MKPointAnnotation()
                annotation.coordinate = location.coordinate
                self.mapView.addAnnotation(annotation)
            }
        }
    })
}

 それぞれの行を見ていきましょう。

 2行目で「PHAsset」クラスの「fetchAssetsWithMediaType」メソッドを使用するとメディアタイプを指定してPHAssetオブジェクトを取得できます。

 fetchAssetsWithMediaTypeメソッドの定義は以下の通りです。

class func fetchAssetsWithMediaType(_ mediaType: PHAssetMediaType,
                            options options: PHFetchOptions!) -> PHFetchResult!

 本連載一回目の記事「開発者が知っておきたいiOS 8の新機能&Xcode 6のインストールと基本的な使い方」でも説明しましたが、PHAssetはフォトライブラリ内の写真のメタデータを保持するオブジェクトです。また、メディアタイプは「PHAssetMediaTypeImage(写真)」を指定しています。

let fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: nil)

Swiftの特徴の一つ「Optional型」とは

 ここで、Swiftの特徴の一つである「Optional型」について説明しましょう。

本記事で扱うクラスに関連する「Optional型」

 PHAssetクラスの「fetchAssetsWithMediaType」メソッドの定義を再度確認してみます。戻り値の型が「PHFetchResult!」となっており、「PHFetchResult」という型名に接尾辞「!」が付いています。

class func fetchAssetsWithMediaType(_ mediaType: PHAssetMediaType,
                            options options: PHFetchOptions!) -> PHFetchResult!

 また、UIViewControllerクラスの「title」プロパティの定義を確認すると、型が「String?」となっており、「String」という型名に接尾辞「?」が付いています。

var title: String?

Optional型とは

 Optional型は、以下の二つの状態を採り得る型で、「値がないかもしれない状況」で使用します。

  • 整数値や文字列などの値を持つ状態
  • 値を持たない状態

 例として、UIViewControllerクラスの「title」プロパティを見てみます。「title」プロパティは「String?型」であり、「String?型」は「Optional<String>型」のシンタックスシュガー(すでに定義されている他の構文の書き換え)です。

var title: String?

 String型として宣言された変数は文字列以外の値を保持できませんが、String?型として宣言された変数は文字列以外にnilを値とすることができます。nilを値とすることで「値を持たない状態」を表します。

var name : String = "Taro"
var title : String? = "Hello Swift"
name = nil  // エラーになる
title = nil // 代入可能

 また、型名に接尾辞「?」を付与して、nilを代入可能にすることを「Optional型でラップする」と呼びます

 例としてString型について説明しましたが、他の型でもOptional型でラップすることによってnilが代入可能になります。プリミティブ値を保持するInt型もラップすることができ、Int?型には数値の他にnilを代入することができます。

Objective-Cとの比較

 「Optional型」はObjective-Cにはなかったコンセプトです。Objective-Cの場合、nilを使用して「値がない状態」を表せます。しかし、これはオブジェクト型に限定したものです。オブジェクト型でない型の場合は「値がない状態」を表す例として、「NSNotFound」などの定数を使用することが挙げられます。

 このようにObjective-Cでは、「値がない状態」の表し方は型ごとに異なっており、使い方によっては想定外の動きが発生して問題になってしまいます。Swiftでは「Optional型」を使用することで、このような問題を解決できます。

Optional型のアンラップ

 自動的にOptional型に変換されるため、Optional型の変数に通常の型の変数を代入することは可能です。

var title : String? = "Hello Swift"

 逆に、通常の型にOptional型の変数を代入することはできません。Optional型の変数はnilを持つ可能性があり、通常の型にnilを代入できないからです。

var title : String? = "Hello Swift"
var name : String = title // エラーになる

 Optional型の変数を通常の型に代入するには、Optional型でラップされた変数を「アンラップ」する必要があります。アンラップするには、以下のように変数に接尾辞「!」を付けます。

var title : String? = "Hello Swift"
var name : String = title!

 アンラップは、変数の内容にかかわらず中身を取り出します。Optional型の変数を通常の型に代入する場合、「!」を使ってアンラップを行う前に、Optional型の変数の値がnilではないことを確認する必要があります。nilに対してアンラップを行うと、ランタイムエラーになってしまいます。

var title : String? = "Hello Swift"
var name : String
if title != nil { // nilチェック
    name = title! // アンラップ
    print("name is \(name)")
}

Optional Binding

 「アンラップを行う前に、Optional型の変数の値がnilではないことを確認する必要がある」と説明しましたが、「Optional Binding」という方法を使えば、もう少し簡潔に記述できます。

 「Optional Binding」はif文やwhile文を使って記述できます。if文を使用する場合のOptional Bindingの形式は以下の通りです。

 まず、条件式右辺のOptional型変数のnilチェックが行われます。変数が値を持つ場合は、アンラップされて左辺の定数に代入され、if文の真の処理が実行されます。それ以外の場合は、偽の処理が行われます。

if let 定数名 = Optional型の変数名 {
    // 処理
}

 以下に例を示します。変数titleは値を持っているので、titleはアンラップされて定数nameに代入され、真の処理が実行されます

var title : String? = "Hello Swift"
if let name = title { // Optional Binding
    print("name is \(name)")
}

Implicitly Unwrapped Optional型

 ここまで「Optional型」について説明しましたが、「Implicitly Unwrapped Optional型」もnilを値とすることができる型です。

 ここで再びPHAssetクラスのfetchAssetsWithMediaTypeメソッドの定義を見てみましょう。

class func fetchAssetsWithMediaType(_ mediaType: PHAssetMediaType,
                            options options: PHFetchOptions!) -> PHFetchResult!

 fetchAssetsWithMediaTypeメソッドの戻り値の型は「PHFetchResult!型」であり、「PHFetchResult!型」は「ImplicitlyUnwrappedOptional<PHFetchResult>型」のシンタックスシュガーです。

 Implicitly Unwrapped Optional型はその名の通り「暗黙のうちにアンラップするOptional型」であり、「Optional型」と違って、アンラップすることなく内包された値にアクセスできます。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。