SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

アップルの新プログラミング言語「Swift」を探検しよう

Swiftの「エクステンション」と「プロトコル」~ 機能と役割、Objective-Cとの違いを知る

アップルの新プログラミング言語「Swift」を探検しよう 第6回


混合プロトコル

 1つの型が複数のプロトコルに準拠している場合、次のような形で型を扱えます。これを混合プロトコルといいます。

protocol<プロトコル名1, プロトコル名2, ...>

 複数のプロトコルに準拠した型としてメソッドの引数などを扱いたい場合には便利です。混合プロトコルの例を見てみましょう。

protocol Countable {
    var count: UInt { get }
}
class TaskMemo: Printable, Countable {
    private var task: String
    init(task: String) {
        self.task = task
    }
    var description: String {
        return self.task
    }
    var count: UInt {
        return UInt(countElements(self.description))
    }
}

func printLongPrintable(printable: protocol<Printable, Countable>) {
    if printable.count > 10 {
        println(printable.description)
    } else {
        println("This printable is not long")
    }
}

printLongPrintable(TaskMemo(task: "go to shop")) // This printable is not long
printLongPrintable(TaskMemo(task: "work to make money")) // work to make money

 この例では、Swiftの標準APIに定義されたPrintableプロトコルと、先ほどの「エクステンションとプロトコルの併用」節で例としたCountableプロトコルに準拠した型を引数に取る関数printLongPrintableを定義しています。

 この関数は、countプロパティが10よりも大きいものに対してはescriptionプロパティでログ出力を行い、そうでないものについては規定の文字列を出力するようになっています。

 Printableプロトコルは次のように宣言されており、準拠する型はdescriptionプロパティを定義することが求められます。

protocol Printable {
    var description: String { get }
}

プロトコルのオプション機能

 Objective-Cと同様に、プロトコルに準拠していても実装することが必須でない場合、プロトコルの宣言の頭に@objcキーワードを、プロトコルのプロパティ、メソッド、subscriptの頭にoptionalキーワードを付けます。これらのキーワードにより、準拠するクラスが、それらのプロパティなどを必ずしも実装しなくてよいことを示せます。

宣言方法
@objc protocol プロトコル名 {
   optional var プロパティ名: 型 { get / get set }
   optional func メソッド名(引数のリスト) -> 返り値の型
   optional subscript(引数のリスト) -> 返り値の型 { get / get set }
}

 なお、イニシャライザに関してはoptionalを先頭に記述できません。イニシャライザが記述されたプロトコルに準拠する型は、必ずそれを実装する必要があります。

 @objcが付いたプロトコルの実装例を見てみましょう。

@objc protocol ListViewDataSource {
    optional var numberOfList: UInt { get }
    optional func titleForElementAtIndex(index: UInt) -> String
}
class ReservationDataSource: ListViewDataSource {
    private var reservations: [String: String]
    init(reservations: [String: String]) {
        self.reservations = reservations
    }
    var numberOfList: UInt {
        return UInt(reservations.count)
    }
}

 この例で宣言しているListViewDataSourceは、各データのタイトルを表示するビューを提供するためのプロトコルです。ListViewDataSourceは自身に準拠するクラスに対して、numberOfListプロパティやtitleForElementAtIndexメソッドを任意で実装するように要求しています。

 ReservationDataSourceクラスは、ListViewDataSourceプロトコルに準拠することでビューの要素数や各要素のタイトルを決められます。また、ReservationDataSourceクラスは予約リストのデータソースをDictionaryを用いて初期化します。

 オプション機能の定義されたプロトコルに準拠した型が実際にオプション機能を実装しているかどうかは、プロトコルのプロパティやメソッドの名前の直後に「?」を付けることでチェックできます。本連載第三回で取り上げたオプショナルチェーンと同様に、チェックの結果はオプショナル列挙型にくるまれた上で渡されます。

 先ほどの例を用いて、プロトコルの型注釈を併用しつつ、そのことを確認してみましょう。

var dataSource: ListViewDataSource = 
    ReservationDataSource(reservations: ["john": "go to shopping"])
dataSource.numberOfList?                 // Some(1)
dataSource.titleForElementAtIndex?(1)    // nil

 dataSource変数はデータ格納時、表面的にはListViewDataSource型として扱われます。実際にそれらが実装されているかどうかは、プロパティやメソッドの後ろに「?」付けてチェックしています。

 dataSource変数の中身はReservationDataSourceオブジェクトで、かつnumberOfListメソッドは実装されているため、「?」を付けたアクセスによって、実装内容の返り値をオプショナル列挙型でくるんだ形(Some(1))で取得できます。

 一方、titleForElementAtIndexメソッドはReservationDataSourceクラスに実装されていないため、呼び出し結果としてnil (=Optional.None) が返ってきます。

次回は

 今回はエクステンションとプロトコルについて扱いました。

 定義済みの型に対して計算プロパティやメソッドを適切な場面に追加すれば、繰り返しのコードも避けられるようになり、よりメンテナンス性の高いコードが実現できます。

 また、プロトコルを用いれば共通の機能を持った型をまとめて扱うことができます。さらに、次回に解説するジェネリクスと組み合わせることで、より汎用的なモジュールを作成できます。

 次回はジェネリクスと演算子を中心とした説明をしていきます。お楽しみに。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
アップルの新プログラミング言語「Swift」を探検しよう連載記事一覧

もっと読む

この記事の著者

yad(ヤド)

クラスメソッド株式会社のアプリケーションエンジニア。iPhoneアプリケーションの開発に2年以上従事している。開発に使用するObjective-Cのみならず、関数型言語Haskellや機械学習などにも関心がある。「Developers.IO」に寄稿した記事の一覧

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/8293 2015/02/05 15:29

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー