Objective-Cのプロトコルとカテゴリの違いを説明できる人はいますか? いつどちらを使用しますか?
7 に答える
プロトコルは、Java のインターフェースと同じものです。本質的には、「このプロトコルを実装するクラスは、これらのメソッドも実装する」という契約です。
一方、カテゴリはメソッドをクラスにバインドするだけです。たとえば、Cocoaでは、クラス (およびもちろんすべてのサブクラス) にNSObject
メソッドを追加できるカテゴリを作成できますが、実際には.NSObject
NSObject
要約すると、プロトコルは、クラスが実装するメソッドを指定します。カテゴリは既存のクラスにメソッドを追加します。
プロトコルを使用して、クラスが実装する必要がある一連のメソッドを宣言し、カテゴリを使用してメソッドを既存のクラスに追加します。
プロトコルには、「実装してほしいいくつかの方法があります」と書かれています。カテゴリには、「これらの追加メソッドを使用して、このクラスの機能を拡張しています」と書かれています。
さて、あなたの混乱は、Apple が「非公式プロトコル」というフレーズを使用したことに起因していると思われます。重要な (そして最も紛らわしい) ポイントは次のとおりです。非公式のプロトコルは、実際にはプロトコルではありません。これは実際には NSObject のカテゴリです。Cocoa は非公式のプロトコルを広く使用して、デリゲートにインターフェイスを提供します。Objective-C 2.0 まではオプションのメソッドが@protocol
構文で許可されていなかったため、Apple は何もしない (またはダミー値を返す) オプションのメソッドと、例外をスローする必須のメソッドを実装しました。コンパイラを介してこれを強制する方法はありませんでした。
現在、Objective-C 2.0 では、@protocol
構文で@optional
キーワードがサポートされ、プロトコルの一部のメソッドがオプションとしてマークされています。したがって、 としてマークされたすべてのメソッドを実装する限り、クラスはプロトコルに準拠します@required
。コンパイラは、クラスが必要なすべてのメソッドを実装しているかどうかも判断できるため、時間を大幅に節約できます。iPhone SDK は、Objective-C 2.0@protocol
構文のみを使用しており、新しい開発でそれを使用しない正当な理由は思いつきません (Mac OS X の以前のバージョンで実行する必要がある Mac OS X Cocoa アプリを除く)。 .
カテゴリー:
カテゴリは、クラス自体を変更せずに、既存のクラスのすべてのインスタンスに新しいメソッドを追加する方法です。
既存のクラスから派生したり、元のクラスを書き直したりせずに、既存のクラスに機能を追加する場合は、カテゴリを使用します。
NSView
cocoa でオブジェクトを使用していて、 のすべてのインスタンスNSView
が何らかのアクションを実行できることを望んでいるとします。明らかに、クラスを書き直すことはできません。クラスから派生したとしても、プログラム内NSView
のすべてのオブジェクトが派生型になるわけではありません。NSView
解決策は、 でカテゴリを作成しNSView
、それをプログラムで使用することです。#import
ヘッダー ファイルにカテゴリ宣言が含まれている限り、すべて NSView
のオブジェクトがカテゴリ ソース ファイルで定義したメソッドに応答するように見えます。
プロトコル:
プロトコルは、任意のクラスが実装することを選択できるメソッドのコレクションです。
特定のクラスが特定のメソッド セットに応答することを保証する場合は、プロトコルを使用します。クラスがプロトコルを採用すると、プロトコル ヘッダーで宣言されたすべてのメソッドを実装することが約束されます。これは、そのクラスを使用する他のクラスは、クラスについて他に何も知る必要なく、それらのメソッドが実装されることを確信できることを意味します。
これは、すべてが共通の「コントローラー」クラスと通信する必要がある類似のクラスのファミリーを作成する場合に役立ちます。コントローラ クラスと被制御クラス間の通信は、すべて 1 つのプロトコルにパッケージ化できます。
補足: object-c 言語は多重継承をサポートしていません (クラスは 1 つのスーパークラスからしか派生できません) が、クラスは複数の異なるプロトコルに準拠できるため、同じ機能の多くをプロトコルで提供できます。
私の理解では、プロトコルは Java のインターフェースに少し似ています。プロトコルはメソッドを宣言しますが、実装は各クラス次第です。カテゴリは Ruby の mixins のようなものです。カテゴリを使用すると、既存のクラスにメソッドを追加できます。組み込みクラスでさえ。
プロトコルを使用すると、特定のクラスやカテゴリに限定されないメソッドのリストを宣言できます。プロトコルで宣言されたメソッドは、任意のクラス/カテゴリを採用できます。プロトコルを採用するクラスまたはカテゴリは、プロトコルで宣言されたすべての必要なメソッドを実装する必要があります。
カテゴリを使用すると、既存のクラスにメソッドを追加できますが、インスタンス変数を追加することはできません。カテゴリが追加するメソッドは、クラス タイプの一部になります。
SGKochan の「Objective-C でのプログラミング」からの定義:
カテゴリー:
カテゴリを使用すると、クラスの定義を関連するメソッドのグループまたはカテゴリに簡単にモジュール化できます。また、クラスの元のソース コードにアクセスしたり、サブクラスを作成したりすることなく、既存のクラス定義を簡単に拡張できます。
プロトコル:
プロトコルは、クラス間で共有されるメソッドのリストです。プロトコルにリストされているメソッドには、対応する実装がありません。それらは他の誰か (あなたのような!) によって実装されることを意図しています。プロトコルは、指定された名前に関連付けられた一連のメソッドを定義する方法を提供します。メソッドは通常、ドキュメント化されているため、メソッドがどのように実行されるかを把握でき、必要に応じて独自のクラス定義に実装できます。プロトコルには、オプションで実装できるメソッドと実装が必要なメソッドのセットがリストされています。特定のプロトコルに必要なすべてのメソッドを実装することを決定した場合、そのプロトコルに準拠または採用すると言われます。すべてのメソッドがオプションであるプロトコル、またはすべてが必須のプロトコルを定義することができます。
プロトコルは、指定されたメソッドを実装するための契約です。プロトコルに準拠するすべてのオブジェクトは、それらのメソッドの実装を提供することに同意します。プロトコルの適切な使用法は、デリゲートの一連のコールバック メソッドを定義することです (デリゲートはすべてのメソッドに応答する必要があります)。
カテゴリは、メソッド (クラスまたはインスタンス メソッド) を追加することにより、現在のオブジェクトを拡張する機能を提供します。カテゴリの適切な使用法は、NSString クラスを拡張して、レシーバーを 1337 5P34K に変換する新しい文字列を作成するメソッドを追加するなど、以前にはなかった機能を追加することです。
NSString *test = @"Leet speak";
NSString *leet = [test stringByConvertingToLeet];