web-dev-qa-db-ja.com

Objective-Cでデリゲートを作成する方法

私は参加者がどのように働くのかを知っています、そして私はどのようにそれらを使うことができるかを知っています。

しかし、どうやってそれらを作成するのですか?

720
Andy Jacobs

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(pre-ARC)で宣言されています。 (たとえば、View Controllerは、多くの場合、それに含まれるViewのデリゲートです。)

あなたのクラスの代表を作る

独自のデリゲートを定義するには、 Apple Docs on protocols で説明されているように、どこかでそれらのメソッドを宣言する必要があります。通常は正式なプロトコルを宣言します。 UIWebView.hから言い換えると、宣言は次のようになります。

@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end

これはインターフェースや抽象基底クラスに似ています。デリゲート用の特別な型、この場合はUIWebViewDelegateを作成するためです。委任実装者はこのプロトコルを採用しなければならないでしょう:

@interface MyClass <UIWebViewDelegate>
// ...
@end

そしてプロトコルのメソッドを実装します。プロトコルで@optionalとして宣言されているメソッド(ほとんどのデリゲートメソッドと同様)については、特定のメソッドを呼び出す前に-respondsToSelector:で確認する必要があります。

ネーミング

デリゲートメソッドは通常、デリゲートクラス名で始まる名前が付けられ、デリゲートオブジェクトを最初のパラメータとして取ります。彼らはまた、意志、べきである、または教義を使用します。たとえば、loadStarted(パラメータをとらない)ではなくwebViewDidStartLoad:(最初のパラメータはWebビューです)。

スピード最適化

メッセージを送信するたびにデリゲートがセレクタに応答するかどうかを確認する代わりに、デリゲートが設定されているときにその情報をキャッシュできます。これを行うための非常にきれいな方法の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

その後、本文で、-respondsToSelector:を何度も送信するのではなく、delegateRespondsTo構造体にアクセスすることで、デリゲートがメッセージを処理していることを確認できます。

非公式代議員

プロトコルが存在する前は、デリゲートが実装できるメソッドを宣言するためにNSObjectcategory を使用するのが一般的でした。たとえば、CALayerはまだこれを行います。

@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end

これは基本的に、どんなオブジェクトでもdisplayLayer:を実装できることをコンパイラに伝えます。

このメソッドを呼び出すには、上記と同じ-respondsToSelector:アプローチを使用します。デリゲートは単にこのメソッドを実装してdelegateプロパティを割り当てるだけです。それで終わりです(あなたがプロトコルに準拠していると宣言することはありません)。この方法はAppleのライブラリでは一般的ですが、新しいコードでは上記のより現代的なプロトコルアプローチを使用する必要があります。このアプローチではNSObjectが汚染されます。

868
Jesse Rusak

承認された答えは素晴らしいですが、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

デリゲートを別のクラス(この場合はUIViewControllerはMyVC)で使用するには、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!");
}
374
Tibidabo

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

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

デリゲートアクセサー(setDelegate)コード内。これは間違いを最小限に抑えるのに役立ちます。

18
umop

たぶんこれはあなたが行方不明になっているものの行に沿っている:

C++のような観点から来ているのであれば、デリゲートは少し慣れていますが、基本的には「うまく機能する」だけです。

それが機能する方法はあなたがNSWindowへのデリゲートとしてあなたが書いたいくつかのオブジェクトを設定することですが、あなたのオブジェクトは多くの可能なデリゲートメソッドの1つまたは少数のための実装(メソッド)を持っているだけです。それで何かが起こり、NSWindowはあなたのオブジェクトを呼びたがっています - それはObjective-cのrespondsToSelectorメソッドを使ってあなたのオブジェクトがそのメソッドを呼んで欲しいかどうかを決定し、そしてそれを呼びます。これがObjective-Cの仕組みです。メソッドはオンデマンドで検索されます。

あなた自身のオブジェクトでこれを行うことは全く簡単です、特別なことは何もありません、例えばあなたは27のオブジェクトのNSArray、すべての異なる種類のオブジェクトを持つことができます、18のそれらだけメソッド-(void)setToBue;を持ちますt。それで、それをする必要がある18のすべての上でsetToBlueを呼び出すために、このようなもの:

for (id anObject in myArray)
{
  if ([anObject respondsToSelector:@selector(@"setToBlue")])
     [anObject setToBlue]; 
}

デリゲートに関する他のことはそれらが保持されていないということですので、あなたは常にあなたのMyClass deallocメソッドでデリゲートをnilにセットしなければなりません。

17
Tom Andersen

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

iOSの委任

2つのViewControllerを作成しました(データを一方から他方へ送信するため)。

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

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で確認する必要があります。

15
Jean

デリゲートを理解すれば、これらの答えはすべて意味があると思います。個人的には私はC/C++の国から来ました、そしてその前にFortran等のような手続き型言語はC++パラダイムの中で同様の類似物を見つけることについての私の2分の話です。

C++/Javaプログラマーにデリゲートを説明しようとしたら、私は言うでしょう

代議員とは何ですか?これらは他のクラス内のクラスへの静的ポインタです。ポインタを割り当てたら、そのクラスの関数/メソッドを呼び出すことができます。したがって、あなたのクラスのいくつかの関数は他のクラスに "委譲"されています(C++の世界ではクラスオブジェクトポインタによって指されるポインタ)。

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

C++で似たようなことをするにはどうすればいいですか。 C++でこれを行おうとした場合は、クラス定義でクラス(オブジェクト)へのポインタを定義してから、それらを他のクラスに配線して、基本クラスへのデリゲートとして追加の機能を提供します。しかし、この配線はコード内で維持する必要があり、不器用でエラーが発生しやすくなります。 Objective Cは、プログラマーがこの問題を解決するのに最善ではないと想定し、クリーンな実装を強制するためのコンパイラ制限を提供します。

10
DrBug

スイフト版

デリゲートは、他のクラスのためにいくらかの働きをする単なるクラスです。これが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つの記事を読むことを強くお勧めします。彼らは私が ドキュメンテーション よりデリケートをもっとよく理解するのを助けました。

9
Suragch

わかりました、これは実際には質問に対する答えではありませんが、あなたがあなた自身のデリゲートを作る方法を探しているなら多分はるかに単純な何かがあなたにとってより良い答えかもしれません。

めったに必要ないので、私は自分の代理人を実装することはほとんどありません。デリゲートオブジェクトには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
Tibidabo

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

@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に準拠するObjective Cクラスを意味します。デリゲートプロパティがweakとして宣言されていることに気付くでしょう。これは保持サイクルを防ぐために非常に重要です(ほとんどの場合、デリゲートは保持しますMyClassインスタンス。したがって、デリゲートを保持として宣言した場合は、両方がお互いを保持し、どちらも解放されません)。

また、プロトコルメソッドがMyClassインスタンスをパラメータとしてデリゲートに渡すことにも気付くでしょう。これは、デリゲートがMyClassインスタンスでいくつかのメソッドを呼び出したい場合のベストプラクティスであり、デリゲートが自身を宣言するときにも役立ちますMyClassDelegateを複数のMyClassインスタンスに、ViewControllerに複数のUITableView'sインスタンスがあり、それらすべてをUITableViewDelegateとして宣言する場合など。

そしてMyClass内で、次のように宣言されたイベントでデリゲートに通知します。

if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
     [_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}

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

8
m.eldehairy

これがデリゲートを作成する簡単な方法です。

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

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

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

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

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

5
Mahesh

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

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

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

ViewController AViewController Bの2つのクラスを持つアプリを見ることができます。 Bには、ViewControllerの背景色をタップで変更する2つのビューがありますが、それほど複雑ではありませんか?クラス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つだけあります。クラス名の最後にWord delegateを追加してプロトコルに名前を付けることをお勧めします。この場合はClassBVCDelegateです。

ステップ2:ClassVBCでプラグママークのステップ2を探し、これを追加します

//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?

ここでは、クラスのデリゲートプロパティを作成します。このプロパティはprotocol型を採用する必要があり、オプションである必要があります。また、サイクルの保持やメモリリークの可能性を避けるために、プロパティの前にweakキーワードを追加する必要があります。その意味がわからない場合は、このキーワードを忘れずに追加してください。

ステップ3:methodのhandleTap ClassBVC内でプラグママークのステップ3を探し、これを追加します

//MARK: step 3 Add the delegate method call here.
delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)

知っておくべきこと、アプリを実行して任意のビューをタップすると、新しい動作は表示されず、正しいことですが、私が指摘したいのは、デリゲートが呼び出されたときにアプリがクラッシュしないことですこれは、オプションの値として作成するためであり、委任がまだ存在していなくてもクラッシュしないためです。では、ClassAVCファイルに移動して、委任します。

ステップ4:ClassAVCのhandleTapメソッド内でプラグママークのステップ4を探し、このようにクラスタイプの隣に追加します。

//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とは何ですか?さて、selfは委任されたClassAVCです!

ステップ6:最後に、ClassAVCでプラグマステップ6を探し、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の関係があることに常に留意してください。

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

3
James Rochabrun

答えは実際に答えられます、しかし私はあなたに代表を作成するための「チートシート」を渡したいと思います:

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
3
Miras Maratuly

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
Lal Krishna

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

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

これはすべてカスタムデリゲートクラスに設定されています。その後、このデリゲートメソッドを好きな場所で使用できます。

それから私のもう一つのviewcontrollerインポートに

このようなデリゲートメソッドを呼び出すためのアクションを作成します

- (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;
}
}
1
User558
//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
Rohit Kashyap

デレゲート: - 作成

@protocol addToCartDelegate <NSObject>

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

@end

データを送信していることを確認するには、送信して委任を割り当ててください

[self.delegate addToCartAction:itemsModel isAdded:YES];
0
Vaibhav Gaikwad

例を挙げましょう。オンラインで製品を購入する場合、それは異なるチームによって処理される配送/配達のようなプロセスを通過します。他の人にとってはオーバーヘッドになるでしょう/ベンダーはこの情報を必要な人だけに渡したいかもしれません。

そのため、アプリの観点から考えると、イベントはオンラインでの注文になることがあり、異なるチームは複数のビューのようになることがあります。

配送チームをShippingView、配送チームをDeliveryViewとした場合のコードを次に示します。

//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
        //
    }
}
0
Ellen