Objective-Cでデリゲートを作成するにはどうすればよいですか?


回答:


889

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];
}

オブジェクトのデリゲートはしばしばそのオブジェクトへの強い参照を保持するため、デリゲートプロパティ自体は通常、保持ループを回避するために(weakARCで)または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
Roland

デリゲートはC ++のようにポリモーフィズムに使用できますか?

@ダンはい、確かに。一般的なプロトコルは、ポリモーフィズムに使用されます。
Jesse Rusak

@JesseRusak「JSSomethingDelegate」は一貫性のために「SomethingDelegate」である必要があると思います:)
HansKnöchelJan

382

承認された回答は素晴らしいですが、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!");
}

4
この回答をクイックリファレンスとして使用すると便利です。しかし、なぜMyClass.hのデリゲートプロパティが 'IBOutlet'とマークされているのですか?
Arno van der Meer 2013

4
@ArnovanderMeer良いキャッチ!なぜか思い出せない。私のプロジェクトでは必要ですが、この例では必要ありません。削除しました。thx
ティビダボ2013

ありがとう。受け入れられた答えと同じように素晴らしく、徹底的に、私はいくつかのコンパクトなサンプルコードから最もよく学びます。2つの答えがあるとよいでしょう。
sudo 2014年

@Tibidabo完全に優れています。みんながこのようなプログラミングの概念を説明してくれることを本当に願っています。私は何年にもわたって「代議員」について何百もの説明を見てきましたが、今までこの理論を実際に理解したことはありません。どうもありがとう...
チャールズ・ロバートソン

5
myClassMyVC.m内のどこにインスタンス化されていますか?
Lane Rettig、2017

18

デリゲートサポートを作成するために正式なプロトコルメソッドを使用すると、次のようなコードを追加することで、適切な型チェック(ただし、コンパイル時ではなく実行時)を確実に行えることがわかりました。

if (![delegate conformsToProtocol:@protocol(MyDelegate)]) {
    [NSException raise:@"MyDelegate Exception"
                format:@"Parameter does not conform to MyDelegate protocol at line %d", (int)__LINE__];
}

デリゲートアクセサー(setDelegate)コード内。これにより、ミスを最小限に抑えることができます。


18

お願いします!デリゲートがiOSでどのように機能するかを理解するには、以下の簡単なステップバイステップチュートリアルを確認してください。

iOSのデリゲート

2つのViewControllerを作成しました(データを相互に送信するため)

  1. FirstViewControllerはデリゲートを実装します(データを提供します)。
  2. SecondViewControllerはデリゲートを宣言します(データを受け取ります)。

17

多分これはあなたが見逃しているものに沿ったものです:

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つの点は、デリゲートが保持されないことです。そのためnilMyClass deallocメソッドでデリゲートを常にに設定する必要があります。


15

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ビュー(デリゲートに準拠している)がオプションのメソッドを実際に実装しているかどうかを確認する必要があります。


11

デリゲートを理解すれば、これらの答えはすべて理にかなっていると思います。個人的に私はC / C ++の土地から来たもので、その前はFortranなどの手続き型言語なので、C ++パラダイムで類似の類似物を見つけるための2分間の取り組みをここで紹介します。

デリゲートをC ++ / Javaプログラマーに説明するとしたら、

デリゲートとは何ですか?これらは、別のクラス内のクラスへの静的ポインターです。ポインタを割り当てると、そのクラスの関数/メソッドを呼び出すことができます。したがって、クラスの一部の関数は別のクラスに「委任」されています(C ++の世界では、クラスオブジェクトポインターによるポインター)。

プロトコルとは何ですか?概念的には、デリゲートクラスとして割り当てるクラスのヘッダーファイルと同様の目的で機能します。プロトコルは、クラス内でポインターがデリゲートとして設定されたクラスに実装する必要があるメソッドを明示的に定義する方法です。

C ++で同様のことをするにはどうすればよいですか?C ++でこれを行おうとした場合は、クラス定義でクラス(オブジェクト)へのポインターを定義し、基本クラスへのデリゲートとして追加の機能を提供する他のクラスにそれらを接続します。ただし、この配線はコード内で修正する必要があり、扱いにくく、エラーが発生しやすくなります。Objective Cは、プログラマーがこの規律を維持するのが得意ではないと想定し、クリーンな実装を実施するためのコンパイラー制限を提供します。


あなたが話しているのは、私が直観について話している間の意味論です。あなたが話しているのは仮想機能ですが、新しい用語に慣れるだけでも難しい場合があります。答えは、C ++ / Cの並列性について考えたい初心者に役立ちます
DrBug

あなたが言っていることは私には本当に明確ではありません。新鮮な応答を書いて、もっと多くの人がそれが便利だと思ったら、投票してもらいませんか?
DrBug 2014

9

Swiftバージョン

デリゲートは、別のクラスのためにいくつかの作業を行う単なるクラスです。これが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!"
}

実際には、デリゲートは次の状況でよく使用されます

  1. クラスが別のクラスに情報を伝達する必要がある場合
  2. クラスが別のクラスにカスタマイズを許可する場合

デリゲートクラスが必要なプロトコルに準拠している場合を除いて、クラスはお互いについて事前に知っている必要はありません。

次の2つの記事を読むことを強くお勧めします。これらは、ドキュメントよりも代理人を理解するのに役立ちました。


8

わかりました。これは実際には質問に対する回答ではありませんが、独自のデリゲートを作成する方法を検討している場合は、はるかに単純なものの方がより適切な回答になる可能性があります。

ほとんど必要ないので、デリゲートをほとんど実装しません。デリゲートオブジェクトに対してデリゲートを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];
}

8

開発したクラスがあり、イベントが発生したときに通知できるようにデリゲートプロパティを宣言したいとします。

@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];
}

デリゲートが実装していないプロトコルが必要な場合でもアプリがクラッシュする場合に備えて、まず、デリゲートがこれから呼び出すプロトコルメソッドに応答するかどうかを確認します。


6

ここにデリゲートを作成する簡単な方法があります

.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]; 
     }
  }

5

独自のデリゲートを作成するには、まずプロトコルを作成し、実装せずに必要なメソッドを宣言する必要があります。次に、このプロトコルを、デリゲートまたはデリゲートメソッドを実装するヘッダークラ​​スに実装します。

プロトコルは次のように宣言する必要があります。

@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];
}

それだけです。このクラスにデリゲートメソッドを実装することで、操作/タスクが完了すると制御が戻ります。


4

免責事項:これはSwiftを作成する方法のバージョンですdelegate

では、デリゲートとは何ですか?…ソフトウェア開発では、特定のコンテキスト内でよく発生する問題の解決に役立つ一般的な再利用可能なソリューションアーキテクチャがあります。これらの「テンプレート」は、いわば設計パターンとして最もよく知られています。デリゲートは、特定のイベントが発生したときに、あるオブジェクトが別のオブジェクトにメッセージを送信できるようにする設計パターンです。オブジェクトAがオブジェクトBを呼び出してアクションを実行するとします。アクションが完了すると、オブジェクトAはBがタスクを完了したことを認識し、必要なアクションを実行する必要があります。これはデリゲートの助けを借りて達成できます!

より良い説明のために、クラス間でデータを渡すカスタムデリゲートを作成する方法を示します。単純なアプリケーションでSwiftを使用し、このスタータープロジェクトをダウンロードまたは複製して実行します。

あなたは、2つのクラスを持つアプリを参照してくださいすることができますViewController AViewController 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のためmethodClassBVC、これを追加

//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、の関数を使用して、protocolfunc 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の関係があることを常に念頭に置いてください。

ここで元のチュートリアルを見ることができます


4

回答は実際には回答されていますが、デリゲートを作成するための「チートシート」を提供したいと思います。

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

2

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{
}

2

私の観点では、そのデリゲートメソッド用に個別のクラスを作成し、必要な場所で使用できます。

私のカスタム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;
}
}

0

委任:-作成

@protocol addToCartDelegate <NSObject>

-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;

@end

送信し、データを送信していることを確認するために代理人を割り当ててください

[self.delegate addToCartAction:itemsModel isAdded:YES];

0
//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);

}


0

例から始めましょう。オンラインで商品を購入した場合、配送/配送などのプロセスが異なるチームによって処理されます。したがって、配送が完了した場合、配送チームは配送チームに通知し、この情報を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
        //
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.