デリゲートがどのように機能するか、そしてどのように使用できるかを知っています。
しかし、それらをどのように作成しますか?
デリゲートがどのように機能するか、そしてどのように使用できるかを知っています。
しかし、それらをどのように作成しますか?
回答:
Objective-Cデリゲートは、delegate
別のオブジェクトのプロパティに割り当てられているオブジェクトです。デリゲートを作成するには、目的のデリゲートメソッドを実装するクラスを定義し、そのクラスをデリゲートプロトコルの実装としてマークします。
たとえば、があるとしますUIWebView
。デリゲートのwebViewDidStartLoad:
メソッドを実装する場合は、次のようなクラスを作成できます。
@interface MyClass<UIWebViewDelegate>
// ...
@end
@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
@end
次に、MyClassのインスタンスを作成し、それをWebビューのデリゲートとして割り当てることができます。
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
UIWebView
側では、デリゲートがwebViewDidStartLoad:
使用してメッセージに応答するかどうかを確認し、必要に応じてrespondsToSelector:
それを送信するために、おそらくこれに似たコードを持っています。
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
オブジェクトのデリゲートはしばしばそのオブジェクトへの強い参照を保持するため、デリゲートプロパティ自体は通常、保持ループを回避するために(weak
ARCで)またはassign
(ARC以前)で宣言されます。(たとえば、ビューコントローラーは多くの場合、ビューコントローラーに含まれるビューのデリゲートです。)
独自のデリゲートを定義するには、プロトコルに関するApple Docsで説明されているように、どこかでメソッドを宣言する必要があります。通常、正式なプロトコルを宣言します。宣言は、UIWebView.hから言い換えると、次のようになります。
@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end
このUIWebViewDelegate
場合、デリゲートの特別な型を作成するため、これはインターフェイスまたは抽象基本クラスに似ています。デリゲートの実装者は、このプロトコルを採用する必要があります。
@interface MyClass <UIWebViewDelegate>
// ...
@end
そして、プロトコルにメソッドを実装します。プロトコルで宣言されているメソッド@optional
(ほとんどのデリゲートメソッドと同様)については-respondsToSelector:
、特定のメソッドを呼び出す前に確認する必要があります。
デリゲートメソッドは通常、デリゲートクラス名で始まる名前が付けられ、デリゲートオブジェクトを最初のパラメーターとして受け取ります。彼らはまた、意志、必要、または形式をしばしば使用します。したがって、webViewDidStartLoad:
(最初のパラメーターはWebビューです)例ではなくloadStarted
(パラメーターを取りません)ではありません。
メッセージを送信するたびにデリゲートがセレクターに応答するかどうかを確認する代わりに、デリゲートが設定されているときにその情報をキャッシュできます。これを行う非常にクリーンな方法の1つは、次のようにビットフィールドを使用することです。
@protocol SomethingDelegate <NSObject>
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end
@interface Something : NSObject
@property (nonatomic, weak) id <SomethingDelegate> delegate;
@end
@implementation Something {
struct {
unsigned int didFinishLoadingItem:1;
unsigned int didFailWithError:1;
} delegateRespondsTo;
}
@synthesize delegate;
- (void)setDelegate:(id <SomethingDelegate>)aDelegate {
if (delegate != aDelegate) {
delegate = aDelegate;
delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
}
}
@end
次に、本文で、デリゲートが何度も何度delegateRespondsTo
も送信-respondsToSelector:
するのではなく、構造体にアクセスしてメッセージを処理することを確認できます。
プロトコルが存在していた前に、それを使用するのが一般的だったカテゴリを上NSObject
デリゲートを実装できるメソッドを宣言すること。たとえば、CALayer
これはまだこれを行います:
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
これは、任意のオブジェクトが実装する可能性があることをコンパイラに通知しますdisplayLayer:
。
次に、-respondsToSelector:
上記と同じ方法でこのメソッドを呼び出します。デリゲートはこのメソッドを実装してdelegate
プロパティを割り当てます。それだけです(プロトコルに準拠していると宣言することはありません)。この方法はAppleのライブラリでは一般的ですが、新しいコードでは上記のより現代的なプロトコルアプローチを使用する必要がありますNSObject
。
unsigned int
のタイプをBOOL
の戻り値としてdelegate respondsToSelector
型ですBOOL
。
承認された回答は素晴らしいですが、1分の回答を探している場合は、これを試してください。
MyClass.hファイルは次のようになります(コメント付きのデリゲート行を追加してください!)
#import <BlaClass/BlaClass.h>
@class MyClass; //define class, so protocol can see MyClass
@protocol MyClassDelegate <NSObject> //define delegate protocol
- (void) myClassDelegateMethod: (MyClass *) sender; //define delegate method to be implemented within another class
@end //end protocol
@interface MyClass : NSObject {
}
@property (nonatomic, weak) id <MyClassDelegate> delegate; //define MyClassDelegate as delegate
@end
MyClass.mファイルは次のようになります。
#import "MyClass.h"
@implementation MyClass
@synthesize delegate; //synthesise MyClassDelegate delegate
- (void) myMethodToDoStuff {
[self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class
}
@end
デリゲートを別のクラス(この場合はMyVCと呼ばれるUIViewController)MyVC.hで使用するには:
#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}
MyVC.m:
myClass.delegate = self; //set its delegate to self somewhere
デリゲートメソッドを実装する
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(@"Delegates are great!");
}
myClass
MyVC.m内のどこにインスタンス化されていますか?
デリゲートサポートを作成するために正式なプロトコルメソッドを使用すると、次のようなコードを追加することで、適切な型チェック(ただし、コンパイル時ではなく実行時)を確実に行えることがわかりました。
if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}
デリゲートアクセサー(setDelegate)コード内。これにより、ミスを最小限に抑えることができます。
多分これはあなたが見逃しているものに沿ったものです:
C ++のような視点から来ている場合、デリゲートは少し慣れる必要がありますが、基本的には「機能するだけ」です。
これが機能する方法は、デリゲートとして作成したオブジェクトをNSWindowに設定することですが、オブジェクトには多くの可能なデリゲートメソッドの1つまたはいくつかの実装(メソッド)しかありません。だから何かが起こり、NSWindow
あなたのオブジェクトを呼びたがっている-それはObjective-cのrespondsToSelector
メソッドを使って、あなたのオブジェクトがそのメソッドを呼びたいかどうかを決定し、それを呼び出すだけだ。これがobjective-cの仕組みです-メソッドはオンデマンドで検索されます。
独自のオブジェクトでこれを行うのは簡単です。特別なことは何もありません。たとえばNSArray
、27のオブジェクト、さまざまな種類のオブジェクトのうち、18だけしかメソッドを-(void)setToBue;
持たないものがあります。他の9にはありません。それで、setToBlue
それを必要とする18のすべてを呼び出すには、次のようにします。
for (id anObject in myArray)
{
if ([anObject respondsToSelector:@selector(@"setToBlue")])
[anObject setToBlue];
}
デリゲートについてのもう1つの点は、デリゲートが保持されないことです。そのためnil
、MyClass dealloc
メソッドでデリゲートを常にに設定する必要があります。
Appleが推奨する良い方法として、デリゲート(定義上はプロトコルです)がNSObject
プロトコルに準拠することは良いことです。
@protocol MyDelegate <NSObject>
...
@end
&デリゲート内にオプションのメソッド(つまり、必ずしも実装する必要のないメソッド)を作成するには、次の@optional
ようなアノテーションを使用できます。
@protocol MyDelegate <NSObject>
...
...
// Declaration for Methods that 'must' be implemented'
...
...
@optional
...
// Declaration for Methods that 'need not necessarily' be implemented by the class conforming to your delegate
...
@end
したがって、オプションとして指定したメソッドを使用する場合は、(クラス内で)respondsToSelector
ビュー(デリゲートに準拠している)がオプションのメソッドを実際に実装しているかどうかを確認する必要があります。
デリゲートを理解すれば、これらの答えはすべて理にかなっていると思います。個人的に私はC / C ++の土地から来たもので、その前はFortranなどの手続き型言語なので、C ++パラダイムで類似の類似物を見つけるための2分間の取り組みをここで紹介します。
デリゲートをC ++ / Javaプログラマーに説明するとしたら、
デリゲートとは何ですか?これらは、別のクラス内のクラスへの静的ポインターです。ポインタを割り当てると、そのクラスの関数/メソッドを呼び出すことができます。したがって、クラスの一部の関数は別のクラスに「委任」されています(C ++の世界では、クラスオブジェクトポインターによるポインター)。
プロトコルとは何ですか?概念的には、デリゲートクラスとして割り当てるクラスのヘッダーファイルと同様の目的で機能します。プロトコルは、クラス内でポインターがデリゲートとして設定されたクラスに実装する必要があるメソッドを明示的に定義する方法です。
C ++で同様のことをするにはどうすればよいですか?C ++でこれを行おうとした場合は、クラス定義でクラス(オブジェクト)へのポインターを定義し、基本クラスへのデリゲートとして追加の機能を提供する他のクラスにそれらを接続します。ただし、この配線はコード内で修正する必要があり、扱いにくく、エラーが発生しやすくなります。Objective Cは、プログラマーがこの規律を維持するのが得意ではないと想定し、クリーンな実装を実施するためのコンパイラー制限を提供します。
デリゲートは、別のクラスのためにいくつかの作業を行う単なるクラスです。これがSwiftでどのように行われるかを示す、少しばかげた(しかしうまくいけば啓発的な)Playgroundの例について、次のコードを読んでください。
// A protocol is just a list of methods (and/or properties) that must
// be used by any class that adopts the protocol.
protocol OlderSiblingDelegate: class {
// This protocol only defines one required method
func getYourNiceOlderSiblingAGlassOfWater() -> String
}
class BossyBigBrother {
// The delegate is the BossyBigBrother's slave. This position can
// be assigned later to whoever is available (and conforms to the
// protocol).
weak var delegate: OlderSiblingDelegate?
func tellSomebodyToGetMeSomeWater() -> String? {
// The delegate is optional because there might not be anyone
// nearby to boss around.
return delegate?.getYourNiceOlderSiblingAGlassOfWater()
}
}
// PoorLittleSister conforms to the OlderSiblingDelegate protocol
class PoorLittleSister: OlderSiblingDelegate {
// This method is repquired by the protocol, but the protocol said
// nothing about how it needs to be implemented.
func getYourNiceOlderSiblingAGlassOfWater() -> String {
return "Go get it yourself!"
}
}
// initialize the classes
let bigBro = BossyBigBrother()
let lilSis = PoorLittleSister()
// Set the delegate
// bigBro could boss around anyone who conforms to the
// OlderSiblingDelegate protocol, but since lilSis is here,
// she is the unlucky choice.
bigBro.delegate = lilSis
// Because the delegate is set, there is a class to do bigBro's work for him.
// bigBro tells lilSis to get him some water.
if let replyFromLilSis = bigBro.tellSomebodyToGetMeSomeWater() {
print(replyFromLilSis) // "Go get it yourself!"
}
実際には、デリゲートは次の状況でよく使用されます
デリゲートクラスが必要なプロトコルに準拠している場合を除いて、クラスはお互いについて事前に知っている必要はありません。
次の2つの記事を読むことを強くお勧めします。これらは、ドキュメントよりも代理人を理解するのに役立ちました。
わかりました。これは実際には質問に対する回答ではありませんが、独自のデリゲートを作成する方法を検討している場合は、はるかに単純なものの方がより適切な回答になる可能性があります。
ほとんど必要ないので、デリゲートをほとんど実装しません。デリゲートオブジェクトに対してデリゲートを1つだけ持つことができます。したがって、通知を使用するよりも、一方向の通信/データの受け渡しにデリゲートが必要な場合。
NSNotificationはオブジェクトを複数の受信者に渡すことができ、非常に使いやすいです。それはこのように動作します:
MyClass.mファイルは次のようになります。
#import "MyClass.h"
@implementation MyClass
- (void) myMethodToDoStuff {
//this will post a notification with myClassData (NSArray in this case) in its userInfo dict and self as an object
[[NSNotificationCenter defaultCenter] postNotificationName:@"myClassUpdatedData"
object:self
userInfo:[NSDictionary dictionaryWithObject:selectedLocation[@"myClassData"] forKey:@"myClassData"]];
}
@end
別のクラスで通知を使用するには:クラスをオブザーバーとして追加します。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];
セレクターを実装します。
- (void) otherClassUpdatedItsData:(NSNotification *)note {
NSLog(@"*** Other class updated its data ***");
MyClass *otherClass = [note object]; //the object itself, you can call back any selector if you want
NSArray *otherClassData = [note userInfo][@"myClassData"]; //get myClass data object and do whatever you want with it
}
オブザーバーとしてクラスを削除することを忘れないでください
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
開発したクラスがあり、イベントが発生したときに通知できるようにデリゲートプロパティを宣言したいとします。
@class myClass;
@protocol myClassDelegate <NSObject>
-(void)myClass:(MyClass*)myObject requiredEventHandlerWithParameter:(ParamType*)param;
@optional
-(void)myClass:(MyClass*)myObject optionalEventHandlerWithParameter:(ParamType*)param;
@end
@interface MyClass : NSObject
@property(nonatomic,weak)id< MyClassDelegate> delegate;
@end
したがって、MyClass
ヘッダーファイル(または別のヘッダーファイル)でプロトコルを宣言し、デリゲートが実装する必要のある/必須のイベントハンドラーを宣言し、次にMyClass
、型(id< MyClassDelegate>
)のプロパティを宣言します。プロトコルMyClassDelegate
では、デリゲートプロパティがweakとして宣言されていることがわかります。これは、保持サイクルを防ぐために非常に重要です(ほとんどの場合、デリゲートはMyClass
インスタンスを保持するため、デリゲートを保持として宣言した場合、両方が互いに保持し、どちらも保持しません。そのうちのいずれかがリリースされます)。
プロトコルメソッドがMyClass
インスタンスをパラメーターとしてデリゲートに渡すことにも気づくでしょう。これは、デリゲートがMyClass
インスタンスでいくつかのメソッドを呼び出す場合のベストプラクティスであり、MyClassDelegate
複数のMyClass
インスタンスがある場合など、デリゲートが複数のインスタンスに対して自身を宣言する場合にも役立ちます。UITableView's
内のインスタンスViewController
とそれ自体UITableViewDelegate
をすべてのインスタンスとして宣言します。
そして、あなたの内側にMyClass
次のように宣言したイベントとデリゲートに通知します:
if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
デリゲートが実装していないプロトコルが必要な場合でもアプリがクラッシュする場合に備えて、まず、デリゲートがこれから呼び出すプロトコルメソッドに応答するかどうかを確認します。
ここにデリゲートを作成する簡単な方法があります
.hファイルにプロトコルを作成します。@classを使用してプロトコルの前に定義され、その後にUIViewControllerの名前が続くことを確認してください。< As the protocol I am going to use is UIViewController class>.
ステップ:1: UIViewControllerクラスのサブクラスとなる「YourViewController」という名前の新しいクラスProtocolを作成し、このクラスを2番目のViewControllerに割り当てます。
ステップ:2: "YourViewController"ファイルに移動して、以下のように変更します。
#import <UIKit/UIkit.h>
@class YourViewController;
@protocol YourViewController Delegate <NSObject>
@optional
-(void)defineDelegateMethodName: (YourViewController *) controller;
@required
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller;
@end
@interface YourViewController : UIViewController
//Since the property for the protocol could be of any class, then it will be marked as a type of id.
@property (nonatomic, weak) id< YourViewController Delegate> delegate;
@end
プロトコルの動作で定義されたメソッドは、プロトコル定義の一部として@optionalおよび@requiredで制御できます。
ステップ:3: デリゲートの実装
#import "delegate.h"
@interface YourDelegateUser ()
<YourViewControllerDelegate>
@end
@implementation YourDelegateUser
- (void) variousFoo {
YourViewController *controller = [[YourViewController alloc] init];
controller.delegate = self;
}
-(void)defineDelegateMethodName: (YourViewController *) controller {
// handle the delegate being called here
}
-(BOOL)delegateMethodReturningBool: (YourViewController *) controller {
// handle the delegate being called here
return YES;
}
@end
//呼び出す前にメソッドが定義されているかどうかをテストします
- (void) someMethodToCallDelegate {
if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
[self.delegate delegateMethodName:self];
}
}
独自のデリゲートを作成するには、まずプロトコルを作成し、実装せずに必要なメソッドを宣言する必要があります。次に、このプロトコルを、デリゲートまたはデリゲートメソッドを実装するヘッダークラスに実装します。
プロトコルは次のように宣言する必要があります。
@protocol ServiceResponceDelegate <NSObject>
- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;
@end
これは、いくつかのタスクを実行する必要があるサービスクラスです。デリゲートを定義する方法とデリゲートを設定する方法を示します。タスクが完了した後の実装クラスでは、デリゲートのメソッドが呼び出されます。
@interface ServiceClass : NSObject
{
id <ServiceResponceDelegate> _delegate;
}
- (void) setDelegate:(id)delegate;
- (void) someTask;
@end
@implementation ServiceClass
- (void) setDelegate:(id)delegate
{
_delegate = delegate;
}
- (void) someTask
{
/*
perform task
*/
if (!success)
{
[_delegate serviceDidFailWithRequestType:@”task failed”];
}
else
{
[_delegate serviceDidFinishedSucessfully:@”task success”];
}
}
@end
これは、デリゲートをそれ自体に設定することによってサービスクラスが呼び出されるメインビュークラスです。また、プロトコルはヘッダークラスに実装されます。
@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}
- (void) go;
@end
@implementation viewController
//
//some methods
//
- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}
それだけです。このクラスにデリゲートメソッドを実装することで、操作/タスクが完了すると制御が戻ります。
免責事項:これはSwift
を作成する方法のバージョンですdelegate
。
では、デリゲートとは何ですか?…ソフトウェア開発では、特定のコンテキスト内でよく発生する問題の解決に役立つ一般的な再利用可能なソリューションアーキテクチャがあります。これらの「テンプレート」は、いわば設計パターンとして最もよく知られています。デリゲートは、特定のイベントが発生したときに、あるオブジェクトが別のオブジェクトにメッセージを送信できるようにする設計パターンです。オブジェクトAがオブジェクトBを呼び出してアクションを実行するとします。アクションが完了すると、オブジェクトAはBがタスクを完了したことを認識し、必要なアクションを実行する必要があります。これはデリゲートの助けを借りて達成できます!
より良い説明のために、クラス間でデータを渡すカスタムデリゲートを作成する方法を示します。単純なアプリケーションでSwiftを使用し、このスタータープロジェクトをダウンロードまたは複製して実行します。
あなたは、2つのクラスを持つアプリを参照してくださいすることができますViewController A
とViewController B
。Bには2つのビューがあり、タップするとの背景色が変わりViewController
ます。複雑すぎませんか。さて、クラスBのビューがタップされたときにクラスAの背景色も変更する簡単な方法を考えてみましょう。
問題は、このビューがクラスBの一部であり、クラスAについて何も知らないということです。そのため、この2つのクラス間で通信する方法を見つける必要があり、そこに委任が有効です。実装を6つのステップに分けたので、必要なときにこれをチートシートとして使用できます。
ステップ1:ClassBVCファイルでプラグママークのステップ1を探し、これを追加します
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
最初のステップはを作成することprotocol
です。この場合、クラスBにプロトコルを作成します。プロトコル内には、実装の要件に基づいて必要な数の関数を作成できます。この場合、UIColor
引数としてオプションを受け入れる単純な関数が1つだけあります。delegate
クラス名の最後に単語を追加してプロトコルに名前を付けることをお勧めします(この場合は)ClassBVCDelegate
。
ステップ2:プラグママークのステップ2を探し、ClassVBC
これを追加する
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
ここでは、クラスのデリゲートプロパティを作成するだけprotocol
です。このプロパティはタイプを採用する必要があり、オプションにする必要があります。また、プロパティの前にウィークキーワードを追加して、保持サイクルと潜在的なメモリリークを回避する必要があります。これが何を意味するのかわからない場合は、このキーワードを忘れずに追加してください。
ステップ3:ルックhandleTap内部プラグママークステップ3のためmethod
でClassBVC
、これを追加
//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
知っておくべきことは、アプリを実行して任意のビューをタップすると、新しい動作は表示されず、正しいことですが、私が指摘したいのは、デリゲートが呼び出されたときにアプリがクラッシュしないことです。これは、オプションの値として作成したためであり、デリゲートがまだ存在していなくてもクラッシュしないのはそのためです。ClassAVC
委任されたファイルに移動して作成しましょう。
ステップ4:のhandleTapメソッド内でプラグママークのステップ4を探し、ClassAVC
これを次のようにクラスタイプの横に追加します。
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
これでClassAVCがClassBVCDelegate
プロトコルを採用しました。コンパイラが「タイプ 'ClassAVCはプロトコル' ClassBVCDelegate 'に準拠していません。これは、プロトコルのメソッドをまだ使用していないことを意味するだけです。想像してみてください。クラスAがプロトコルを採用する場合は、クラスBとの契約に署名するようなものであり、この契約では「私を採用するクラスはすべて自分の機能を使用する必要があります!」
クイックノート: Objective-C
背景いる場合は、おそらくそのエラーをシャットダウンしてそのメソッドをオプションにすることもできると考えているでしょうが、驚いたことに、おそらくあなたのSwift
言語では、言語がオプションをサポートしていないためprotocols
、作成することができますの拡張機能、protocol
またはprotocol
実装で@objcキーワードを使用します。
個人的に、異なるオプションのメソッドを使用してプロトコルを作成する必要がある場合protocols
、それを別のに分割したいので、オブジェクトに1つの責任を与えるという概念に従いますが、特定の実装に基づいて異なる場合があります。
ここにオプションのメソッドについての良い記事があります。
ステップ5:セグエメソッドの準備内でプラグママークのステップ5を探し、これを追加する
//MARK: step 5 create a reference of Class B and bind them through the `prepareforsegue` method.
if let nav = segue.destination as? UINavigationController, let classBVC = nav.topViewController as? ClassBVC {
classBVC.delegate = self
}
ここでは単にインスタンスを作成しています ClassBVC
そのデリゲートをselfに割り当ててい、ここではselfとは何ですか?えーと、ClassAVC
委任されたのは自己です!
ステップ6:最後に、ステップ6でプラグマを探しClassAVC
、の関数を使用して、protocol
func changeBackgroundColorと入力すると、自動補完されていることがわかります。その中に任意の実装を追加できます。この例では、背景色を変更し、これを追加します。
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
今すぐアプリを実行してください!
Delegates
どこにでもあり、おそらくあなたは予告なしにそれらを使用します。tableview
過去に委任を作成した場合UIKIT
、それらを取り巻く多くのクラスの作業や他の多くのものframeworks
も、これらの主な問題を解決します。
おめでとうございます。カスタムデリゲートを実装するだけです。おそらく考えていることでしょう。まあ、委任は、あなたがiOS
開発者であり、オブジェクト間に1対1の関係があることを常に念頭に置いてください。
回答は実際には回答されていますが、デリゲートを作成するための「チートシート」を提供したいと思います。
DELEGATE SCRIPT
CLASS A - Where delegate is calling function
@protocol <#Protocol Name#> <NSObject>
-(void)delegateMethod;
@end
@interface <#Some ViewController#> : <#UIViewController#>
@property (nonatomic, assign) id <<#Protocol Name#>> delegate;
@end
@implementation <#Some ViewController#>
-(void)someMethod {
[self.delegate methodName];
}
@end
CLASS B - Where delegate is called
@interface <#Other ViewController#> (<#Delegate Name#>) {}
@end
@implementation <#Other ViewController#>
-(void)otherMethod {
CLASSA *classA = [[CLASSA alloc] init];
[classA setDelegate:self];
}
-delegateMethod() {
}
@end
ViewController.h
@protocol NameDelegate <NSObject>
-(void)delegateMEthod: (ArgType) arg;
@end
@property id <NameDelegate> delegate;
ViewController.m
[self.delegate delegateMEthod: argument];
MainViewController.m
ViewController viewController = [ViewController new];
viewController.delegate = self;
方法:
-(void)delegateMEthod: (ArgType) arg{
}
私の観点では、そのデリゲートメソッド用に個別のクラスを作成し、必要な場所で使用できます。
私のカスタムDropDownClass.h
typedef enum
{
DDSTATE,
DDCITY
}DropDownType;
@protocol DropDownListDelegate <NSObject>
@required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString DropDownType:(DropDownType)dropDownType;
@end
@interface DropDownViewController : UIViewController
{
BOOL isFiltered;
}
@property (nonatomic, assign) DropDownType dropDownType;
@property (weak) id <DropDownListDelegate> delegate;
@property (strong, nonatomic) NSMutableArray *array1DropDown;
@property (strong, nonatomic) NSMutableArray *array2DropDown;
その後、in.mファイルはオブジェクトを含む配列を作成し、
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGFloat rowHeight = 44.0f;
return rowHeight;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return isFiltered?[self.array1DropDown count]:[self.array2DropDown count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = @"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (self.delegate) {
if (self.dropDownType == DDCITY) {
cell.textLabel.text = [self.array1DropDown objectAtIndex:indexPath.row];
}
else if (self.dropDownType == DDSTATE) {
cell.textLabel.text = [self.array2DropDown objectAtIndex:indexPath.row];
}
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissViewControllerAnimated:YES completion:^{
if(self.delegate){
if(self.dropDownType == DDCITY){
[self.delegate dropDownDidSelectItemWithString:[self.array1DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
else if (self.dropDownType == DDSTATE) {
[self.delegate dropDownDidSelectItemWithString:[self.array2DropDown objectAtIndex:indexPath.row] DropDownType:self.dropDownType];
}
}
}];
}
ここですべてがカスタムデリゲートクラスに設定されています。その後、このデリゲートメソッドを必要な場所で使用できます。たとえば...
その後、別のビューコントローラのインポートで
このようなデリゲートメソッドを呼び出すアクションを作成する
- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}
その後、このようにデリゲートメソッドを呼び出します
- (void)dropDownDidSelectItemWithString:(NSString *)itemString DropDownType:(DropDownType)dropDownType {
switch (dropDownType) {
case DDCITY:{
if(itemString.length > 0){
//Here i am printing the selected row
[self.dropDownBtn1 setTitle:itemString forState:UIControlStateNormal];
}
}
break;
case DDSTATE: {
//Here i am printing the selected row
[self.dropDownBtn2 setTitle:itemString forState:UIControlStateNormal];
}
default:
break;
}
}
委任:-作成
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
送信し、データを送信していることを確認するために代理人を割り当ててください
[self.delegate addToCartAction:itemsModel isAdded:YES];
//1.
//Custom delegate
@protocol TB_RemovedUserCellTag <NSObject>
-(void)didRemoveCellWithTag:(NSInteger)tag;
@end
//2.
//Create a weak reference in a class where you declared the delegate
@property(weak,nonatomic)id <TB_RemovedUserCellTag> removedCellTagDelegate;
//3.
// use it in the class
[self.removedCellTagDelegate didRemoveCellWithTag:self.tag];
//4. import the header file in the class where you want to conform to the protocol
@interface MyClassUsesDelegate ()<TB_RemovedUserCellTag>
@end
// 5。クラスにメソッドを実装します。.m-(void)didRemoveCellWithTag:(NSInteger)tag {NSLog @( "Tag%d"、tag);
}
例から始めましょう。オンラインで商品を購入した場合、配送/配送などのプロセスが異なるチームによって処理されます。したがって、配送が完了した場合、配送チームは配送チームに通知し、この情報を1対1のコミュニケーションとして伝える必要があります。他の人にとってはオーバーヘッドになるでしょう/ベンダーはこの情報を必要な人にだけ渡したいと思うかもしれません。
したがって、アプリの観点から考えると、イベントはオンライン注文であり、異なるチームは複数のビューのようになる可能性があります。
以下は、ShippingViewをShipping Teamとして、DeliveryViewをDelivery Teamと見なすコードです。
//Declare the protocol with functions having info which needs to be communicated
protocol ShippingDelegate : class {
func productShipped(productID : String)
}
//shippingView which shows shipping status of products
class ShippingView : UIView
{
weak var delegate:ShippingDelegate?
var productID : String
@IBAction func checkShippingStatus(sender: UIButton)
{
// if product is shipped
delegate?.productShipped(productID: productID)
}
}
//Delivery view which shows delivery status & tracking info
class DeliveryView: UIView,ShippingDelegate
{
func productShipped(productID : String)
{
// update status on view & perform delivery
}
}
//Main page on app which has both views & shows updated info on product whole status
class ProductViewController : UIViewController
{
var shippingView : ShippingView
var deliveryView : DeliveryView
override func viewDidLoad() {
super.viewDidLoad()
// as we want to update shipping info on delivery view, so assign delegate to delivery object
// whenever shipping status gets updated it will call productShipped method in DeliveryView & update UI.
shippingView.delegate = deliveryView
//
}
}