Objective-Cの第六歩 プロトコルの宣言と実装
公開日:
:
iOSアプリを書く! Objective-C, オブジェクト指向
Objective-Cの第五歩では、親クラスの継承とメソッドのオーバーライドについて説明した。そこまで説明すれば、新規iOSアプリケーションを作成した際に書いてあるコードを読み解くことができる、と思っていたのだけれど、もう一つ説明しておかなければならないものがあるということに気付いた。それがプロトコルという仕組みである。
プロトコルとは?何故プロトコルが必要なの?
プロトコルという仕組みについては、自分一人で小規模アプリケーションを書いていく場合には、全く知らなくてもなんとかなる。一方、Appleを含めたプロフェッショナルな他者が書いたコードを読み解く場合には、知っておいた方が良い。というのも、プロトコルというのは大規模なアプリケーションやフレームワークにおいて、多数のクラス間の関係性をスッキリさせるための仕組みだからである。
たとえば、前回のGaussTesterの例であれば、StudentクラスとGaussクラスの間には親子関係があった。実際に擬人化して考えてみても、小学生GaussはStudentに内包されるから、これは自然な関係であると言えよう。
ただ、Gaussは数学者(Mathematician)でもあり、Mathematicianクラスで宣言されたメソッドも使用したいとなったときに、困ってしまう。Objective-Cではクラスの多重継承と呼ばれる、複数のクラスを親クラスとした継承が出来ないので、どちらかの継承を諦めざるを得ない。
これは不便な制約のように思えるが、Objective-Cではこうした制約をつけることにより菱形継承と呼ばれる多重継承によって生じる問題を回避している。たとえばStudentクラスとMathematicianクラスが共通の親クラスPersonを持っていた場合、Personの特定メソッドをそれぞれ別の実装でオーバーライドしている可能性があるわけで、Gaussがそのメソッドを呼び出すときにどちらの実装を参照すれば良いのか不透明になってしまう。これが菱形継承という問題だ。
プロトコルを宣言する書式
そこで、多重継承が出来ない代わりに、プロトコルという仕組みが用意されている。プロトコルとは実装を持たないメソッド宣言の集まりで、1つのクラスに対して、複数のプロトコルを採用することが出来る。PHPやJavaのインターフェイスと同様の仕組みである。
プロトコルの宣言は以下のように行う。
@protocol Person @required - (void)eat; @optional - (void)sleep; @end |
プロトコル宣言を表すコンパイラディレクティブは、@protocolであり、@endまでの間でメソッドの宣言を行う。@requiredの後に続くのは、このプロトコルを採用したクラスで実装が必須となるメソッド、@optionalの後に続くのは実装が任意のメソッドである。ちなみに@requiredも@optionalもつけずにメソッド宣言を行った場合、@optionalとして扱われる。
プロトコル採用の書式
このようにして宣言したプロトコルを採用する場合、宣言部で親クラスの指定に続いて、”<>“に囲むような形でプロトコル名を書く。
#import "Student.h" #import "Person.h" @interface Gauss : Student <Person> - (int)summary0ToX:(int)x withGap:(int)gap; @end |
ここではPerson.hというファイルでPersonプロトコルの宣言をしてある体になっているが、別に宣言部で読み込めるファイルならどのファイルで宣言しても良い。たとえば複数のプロトコルを1ファイルで宣言して、Protocols.hなどの名前のファイルを作って読み込んでも良い。
なお、1つのクラスに対して複数のプロトコルを採用する場合は、”<>“に囲まれた中でカンマ(”,”)区切りでプロトコル名を書く。
実装部では、採用したプロトコルの@requiredになっているメソッドは必ず実装しなければならない。
#import "Gauss.h" @implementation Gauss - (int)summary0ToX:(int)x withGap:(int)gap{ int sum=0; sum = (x + x%gap)*(x/gap + 1)/2; return sum; } - (void)eat{ } //sleepメソッドは@optionalなので実装しなくても良い @end |
これがプロトコルの仕組みである。
メソッドがとる引数をプロトコルで限定する
プロトコルには、多重継承問題の解決以外にも役割がある。それは、メソッドがオブジェクトを引数としてとる場合に、与えられた引数オブジェクトに実装内で呼び出すメソッドがちゃんと存在しているかどうかのチェックが出来るのである。
たとえば、以下のようなケース。
@implementation someOtherClass - (void)someOtherMethod:(id)x{ [x eat]; } @end |
引数として受け取ったオブジェクトの、eatメソッドを呼び出している。この書き方だと、引数のオブジェクトに本当にeatメソッドが存在しているか保証されないので、指定メソッドが見当たらないというエラーになってしまう可能性がある。
そこで、引数にもプロトコルを指定しておくことで、そのプロトコルを採用していない引数を受け取ることを防ぐ。
@implementation someOtherClass - (void)someOtherMethod:(id <Person>)x{ [x eat]; } @end |
このように書くと、Personプロトコルの中でeatメソッドは@requiredとされていたので、eatメソッドの実装が保証されるのである。
以上がObjective-Cのプロトコルである。最初に書いたように、小規模自家製アプリケーションなどでは全く使うことを考えなくて良いというか、設計の泥沼に入り込んでしまう可能性があるので、触れない方が良い。無視してAll right。
関連記事
-
Objective-Cの第三歩 クラスとクラスメソッドを定義する
Swiftの事をひとまず置いておいてObjective-Cの入門編を書いているわけだが、前々回の"H
-
Objective-Cの第一歩(仕切り直し)
前回Objective-Cの第一歩として挙げたコードであるが、綺麗さっぱり忘れてほしい。というのは、
-
Xcode 6の正式リリースまでに、Objective-Cでアプリを一つ仕上げる!
Swiftに早速触れてみたい!でもXcode 6がベータ版の間は、有料(7800円/年)のDevel
-
Objective-CでiOSアプリの第一歩 新規プロジェクトで生成されるコードの解説
しけたコンソールアプリばかり作っていたけれど、ようやっとiOSプログラミングに入るとしよう。急がない
-
Objective-Cの第五歩 クラスの継承とメソッドのオーバーライド
前回Objective-Cの第四歩では、等差数列の和を計算するプログラムGaussTesterの作成
-
Objective-CでiOSアプリの第三歩 UIViewControllerの必要性を理解する
前回はUIViewControllerの存在を無視して"Hello, World!"アプリケーション
-
Objective-Cでは何故.hファイルと.mファイルを作成させられるのか
前回説明したように、Objective-Cでプログラムを書く際には、別にC言語そのもののつもりで書い
-
Objective-CでiOSアプリの第二歩 とにかく立ち上がればというレベルのHello, World!アプリを作成
前回はiOSアプリ作成の第一歩として、Empty Applicationを選択した際に書いてあるコー
-
Objective-Cの第四歩 インスタンスプロパティ・メソッドを定義する
Objective-Cの第三歩では、ピュアC言語からのObjective-Cのクラス入門ということで
-
iOSプログラミング入門書では、まず最初のHello, World!すら難しい
Hello, World!が第一歩 新しくプログラミング言語を習得するときに、「この言語でのH