web-dev-qa-db-ja.com

プロトコルとデリゲートは正確に何であり、IOSでどのように使用されますか?

私はデリゲートとプロトコルの概念について本当に混乱しています。 Javaのインターフェースおよびアダプタークラスと同等ですか?彼らはどのように機能しますか?これまでに読んだリソースはどれも役に立たなかった。 「委任とは、プログラム内の1つのオブジェクトが別のオブジェクトに代わって、または別のオブジェクトと連携して動作する単純で強力なパターンです。それに。」これが何を意味するのか分かりません。誰かが彼らが何であるかを説明し、簡単な例を与えることができますか?前もって感謝します!

編集:

私の知る限り、

1)デリゲートはプロトコル(インターフェースの別名)を実装します

2)オブジェクトがデリゲートを登録する(プロトコルを実装する)

3)オブジェクトはデリゲートでプロトコルメソッドを呼び出すことができます

したがって、デリゲートはオブジェクトをプロトコルに接続しています。

私が間違っている場合は修正してください。

オブジェクト自体がプロトコルを実装できない理由がまだわかりません。ずっと簡単だったかもしれません!

20
Oleksiy

プロトコルは、クラスの1つを使用したい場合に、クラスに実装するメソッドのセットを指定する方法です。 UITableViewDelegateやUITableViewDataSourceなどのデリゲートとデータソースは、まさにプロトコルです。

この方法でプロトコルを指定します。

@protocol MyProtocol <NSObject>

- (void)aRequiredMethod;

@required
- (void)anotherRequiredMethod;

@optional
- (void)anOptionalMethod;

@end

@requiredの後または他の指定子の前に宣言されたメソッドは必須であり、プロトコルを使用するクラスはそれらすべてを実装する必要があります。 @optional指定子の後に宣言することにより、いくつかのオプションのメソッドを宣言することもできます。

次に、クラスのインターフェイスで、クラスがプロトコルに「適合する」ことを指定できます(必要なメソッドを実装します)。

@interface MyClass <MyProtocol>

@end

通常、プロパティを使用して、プロトコルに準拠するオブジェクトへの参照を保持します。たとえば、デリゲートを追跡するには:

@property (nonatomic, weak) id<MyProtocol> delegate;

この時点で、コード内で、参照を保持し、他のメソッドと同様にプロトコルを実装するオブジェクトで呼び出すメソッドを呼び出す必要があります。

[self.delegate aRequiredMethod];

オブジェクトがプロトコルに準拠しているかどうかを確認するには、呼び出すことができます

[self.delegate conformsToProtocol:@protocol(MyProtocol)]

オブジェクトがメソッドを実装しているかどうかを確認するには、呼び出すことができます

[self.delegate respondsToSelector:@selector(anOptionalMethod)]

詳細については、Appleのガイドを参照してください Working With Protocols

44

(@protocol syntax in Objective-C)で宣言されたプロトコルは、 "採用"(このプロトコルを使用することを宣言)するクラスが実装する一連のメソッドの宣言に使用されます。これは、「特定のプロトコルを実装する限り、どのクラスが使用されるかは気にしない」ことをコードで指定できることを意味します。これは、Objective-Cで次のように実行できます。

id<MyProtocol> instanceOfClassThatImplementsMyProtocol;

コードでこれを指定すると、プロトコルMyProtocolに「準拠する」任意のクラスを変数instanceOfClassThatImplementsMyProtocolで使用できます。つまり、この変数を使用するコードは、クラスが何であるかに関係なく、この特定の変数でMyProtocolで定義されているメソッドを使用できることを認識しています。これは、継承の設計パターンを回避する優れた方法であり、密結合を回避します。

デリゲートは、プロトコルの言語機能の使用です。委任設計パターンは、必要に応じてプロトコルを使用するようにコードを設計する方法です。 Cocoaフレームワークでは、デリゲートデザインパターンを使用して、特定のプロトコルに準拠するクラスのインスタンスを指定します。この特定のプロトコルは、特定のイベントで特定のアクションを実行するためにデリゲートクラスが実装するメソッドを指定します。デリゲートを使用するクラスは、そのデリゲートがプロトコルと一致することを知っているため、特定の時間に実装されたメソッドを呼び出すことができることを知っています。この設計パターンは、あるデリゲートインスタンスを別のデリゲートインスタンスと非常に簡単に交換できるため、クラスを分離するのに最適な方法です。プログラマは、置換インスタンスまたはクラスが必要なプロトコルに準拠していることを確認するだけです(つまり、プロトコルで指定されたメソッド)!

プロトコルとデリゲートは、Objective-CとMac/iOSの開発だけに限定されませんが、Objective-C言語とAppleフレームワークはこの素晴らしい言語機能とデザインパターンを多用します。

編集:

この例を見つけてください。 Cocoa TouchのUIKit frameworkには、UITextFieldDelegateプロトコルがあります。このプロトコルは、UITextFieldインスタンスのデリゲートであるクラスが実装する一連のメソッドを定義します。つまり、デリゲートをUITextFieldに(デリゲートプロパティを使用して)割り当てたい場合、このクラスがUITextFieldDelegateに準拠していることを確認する必要があります。実際、UITextFieldのデリゲートプロパティは次のように定義されているためです。

@property(nonatomic, assign) id<UITextFieldDelegate> delegate

次に、プロトコルを実装しないクラスを割り当てると、コンパイラーは警告を出します。これは本当に便利です。クラスがプロトコルを実装していると述べる必要があり、それが実装されていると言って、クラスと特定の方法でやり取りできることを他のクラスに知らせています。したがって、MyTextFieldDelegateClassのインスタンスをUITextFieldのデリゲートプロパティに割り当てると、UITextFieldは、特定のメソッド(テキスト入力、選択などに関連する)を呼び出すことができることを認識します。 )のMyTextFieldDelegateClassMyTextFieldDelegateClassUITextFieldDelegateプロトコルを実装すると言っているため、これを知っています。

最終的に、これはすべて、プロジェクトのコードの柔軟性と適応性を大幅に向上させます。このテクノロジを使用すると、すぐに気付くはずです。 :)

10

最も単純な形式では、デリゲートは別のオブジェクトからメッセージを受け取るオブジェクトです。そして、あなたはいつもそれをします。

エンジンを搭載した車のオブジェクトがあるとします。

@interface car : NSObject

@property (nonatomic) id engine;

@end

したがって、エンジンに開始メッセージを転送できます。

[_engine start];

エンジンはデリゲートとして機能しており、メッセージを渡すだけです。

プロトコルはそれをより形式的にし、Xcodeは必要なまたはオプションのメソッドに準拠していることをチェックします。

@property (nonatomic) id <engineDelegate> engine;

エンジンオブジェクトには、startを要求するプロトコル定義が含まれているため、関数startを含める必要があると述べています。

@protocol engineDelegate 
 - (void) start;
@optional
 - (double) fuelLevel;
@end

デリゲートとプロトコルがなぜこんなにクールなのですか?エンジンは、実行時に使用できる任意の数の異なるエンジンである可能性があるため、プロトコルに準拠している限り、ジェットエンジン、燃焼エンジン、重要ではない位相変調エンジンである可能性があります。そして、デリゲートをクラスインターフェイスに追加することにより、Xcodeが準拠することを伝えます。

@interface timeWarpDrive : NSObject <engineDelegate>
9
Chris