webentwicklung-frage-antwort-db.com.de

Wie erstelle ich Delegaten in Objective-C?

Ich weiß, wie Delegierte arbeiten und wie ich sie einsetzen kann.

Aber wie erstelle ich sie?

733
Andy Jacobs

Ein Objective-C-Delegat ist ein Objekt, das der Eigenschaft delegate ein anderes Objekt zugewiesen wurde. Um eine zu erstellen, definieren Sie einfach eine Klasse, die die Delegatmethoden implementiert, an denen Sie interessiert sind, und markieren diese Klasse als Implementierung des Delegatprotokolls.

Angenommen, Sie haben ein UIWebView. Wenn Sie die webViewDidStartLoad: -Methode des Delegaten implementieren möchten, können Sie eine Klasse wie die folgende erstellen:

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

@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView { 
    // ... 
}
@end
_

Dann können Sie eine Instanz von MyClass erstellen und als Stellvertreter der Webansicht zuweisen:

_MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
_

Auf der Seite UIWebView hat es wahrscheinlich einen ähnlichen Code, um festzustellen, ob der Delegat auf die Nachricht _webViewDidStartLoad:_ mit respondsToSelector: antwortet und sendet es gegebenenfalls.

_if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
    [self.delegate webViewDidStartLoad:self];
}
_

Die Delegate-Eigenschaft selbst wird normalerweise als weak (in ARC) oder assign (vor ARC) deklariert, um Beibehaltungsschleifen zu vermeiden, da der Delegate eines Objekts häufig einen starken Verweis auf dieses Objekt enthält. (Ein Ansichtscontroller ist beispielsweise häufig der Stellvertreter einer darin enthaltenen Ansicht.)

Stellvertretungen für Ihre Klassen

Um Ihre eigenen Delegaten zu definieren, müssen Sie ihre Methoden irgendwo deklarieren, wie in den Apple Docs on protocols beschrieben. Normalerweise deklarieren Sie ein formelles Protokoll. Die in UIWebView.h umschriebene Deklaration würde folgendermaßen aussehen:

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

Dies ist analog zu einer Schnittstelle oder einer abstrakten Basisklasse, da hier ein spezieller Typ für Ihren Delegaten erstellt wird, UIWebViewDelegate. Delegierte Implementierer müssten dieses Protokoll übernehmen:

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

Und dann implementieren Sie die Methoden im Protokoll. Bei Methoden, die im Protokoll als _@optional_ deklariert sind (wie die meisten Delegierungsmethoden), müssen Sie mit _-respondsToSelector:_ prüfen, bevor Sie eine bestimmte Methode aufrufen.

Benennung

Delegierungsmethoden werden normalerweise beginnend mit dem Namen der delegierenden Klasse benannt und nehmen das delegierende Objekt als ersten Parameter. Sie benutzen auch oft eine Willens-, Soll- oder Didform. Also, _webViewDidStartLoad:_ (erster Parameter ist die Webansicht) anstatt loadStarted (ohne Parameter).

Geschwindigkeitsoptimierungen

Anstatt zu überprüfen, ob ein Delegat jedes Mal auf eine Auswahl reagiert, wenn wir eine Nachricht senden möchten, können Sie diese Informationen zwischenspeichern, wenn Delegaten festgelegt werden. Eine sehr saubere Möglichkeit, dies zu tun, ist die Verwendung eines Bitfelds wie folgt:

_@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
_

Anschließend können wir im Text prüfen, ob unser Delegat Nachrichten verarbeitet, indem wir auf unsere delegateRespondsTo -Struktur zugreifen, anstatt immer wieder _-respondsToSelector:_ zu senden.

Informelle Delegierte

Bevor Protokolle existierten, war es üblich, eine Kategorie für NSObject zu verwenden, um die Methoden zu deklarieren, die ein Delegat implementieren konnte. Zum Beispiel macht CALayer immer noch Folgendes:

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

Dies teilt dem Compiler im Wesentlichen mit, dass jedes Objekt _displayLayer:_ implementieren kann.

Sie würden dann den gleichen _-respondsToSelector:_ -Ansatz wie oben beschrieben verwenden, um diese Methode aufzurufen. Die Delegierten implementieren diese Methode einfach und weisen die Eigenschaft delegate zu. Das ist alles (es gibt keine Erklärung, dass Sie einem Protokoll entsprechen). Diese Methode ist in Apples Bibliotheken üblich, neuer Code sollte jedoch den oben beschriebenen, moderneren Protokollansatz verwenden, da dieser Ansatz NSObject verschmutzt (was die automatische Vervollständigung weniger nützlich macht) und es dem Compiler erschwert, Sie vor Tippfehlern und Ähnlichem zu warnen fehler.

875
Jesse Rusak

Die genehmigte Antwort ist großartig, aber wenn Sie nach einer 1-minütigen Antwort suchen, versuchen Sie Folgendes:

Die MyClass.h-Datei sollte folgendermaßen aussehen (fügen Sie Stellvertreterzeilen mit Kommentaren hinzu!)

#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

Die Datei MyClass.m sollte so aussehen

#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

So verwenden Sie Ihren Delegaten in einer anderen Klasse (in diesem Fall UIViewController mit dem Namen 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

Implementieren Sie die Delegate-Methode

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}
377
Tibidabo

Bei Verwendung der formalen Protokollmethode zum Erstellen der Delegatenunterstützung habe ich festgestellt, dass Sie eine ordnungsgemäße Typprüfung (allerdings zur Laufzeit, nicht zur Kompilierungszeit) sicherstellen können, indem Sie Folgendes hinzufügen:

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

im Code Ihres delegierten Accessors (setDelegate). Dies hilft, Fehler zu minimieren.

18
umop

Vielleicht ist dies eher so, wie Sie es vermissen:

Wenn Sie aus einer C++ ähnlichen Perspektive kommen, sind die Delegierten etwas gewöhnungsbedürftig - aber im Grunde arbeiten sie einfach.

Die Funktionsweise besteht darin, dass Sie ein Objekt festlegen, das Sie als Delegat für NSWindow geschrieben haben, Ihr Objekt jedoch nur Implementierungen (Methoden) für eine oder einige der vielen möglichen Delegatmethoden enthält. Es passiert also etwas und NSWindow möchte Ihr Objekt aufrufen - es verwendet lediglich die respondsToSelector -Methode von Objective-c, um zu bestimmen, ob Ihr Objekt diese Methode aufrufen möchte, und ruft sie dann auf. So funktioniert object-c - Methoden werden bei Bedarf nachgeschlagen.

Es ist völlig trivial, dies mit eigenen Objekten zu tun, da ist nichts Besonderes los, Sie könnten zum Beispiel ein NSArray von 27 Objekten haben, alle Arten von Objekten, von denen nur 18 die Methode -(void)setToBue; haben andere 9 nicht. Also, um setToBlue für alle 18 anzurufen, die es erledigen müssen, ungefähr so:

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

Die andere Sache über Delegaten ist, dass sie nicht beibehalten werden, so dass Sie den Delegaten immer auf nil in Ihrer MyClass dealloc -Methode festlegen müssen.

17
Tom Andersen

Bitte! Im folgenden einfachen Lernprogramm erfahren Sie Schritt für Schritt, wie Delegierte unter iOS arbeiten.

Delegieren in iOS

Ich habe zwei ViewController erstellt (zum Senden von Daten von einem zum anderen)

  1. FirstViewController-Implementierungsdelegierter (der Daten bereitstellt).
  2. SecondViewController deklariert den Delegaten (der Daten empfängt).
17
swiftBoy

Als bewährte Methode, die von Apple empfohlen wird, empfiehlt es sich, dass der Delegat (per Definition ein Protokoll) das Protokoll NSObject einhält.

@protocol MyDelegate <NSObject>
    ...
@end

& Um optionale Methoden in Ihrem Delegaten zu erstellen (d. h. Methoden, die nicht unbedingt implementiert werden müssen), können Sie die Annotation @optional wie folgt verwenden:

@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

Wenn Sie also Methoden verwenden, die Sie als optional angegeben haben, müssen Sie (in Ihrer Klasse) mit respondsToSelector prüfen, ob die Ansicht (die Ihrem Delegaten entspricht) Ihre optionalen Methoden tatsächlich implementiert hat oder nicht.

15
Jean

Ich denke, all diese Antworten sind sehr sinnvoll, sobald Sie die Delegierten verstanden haben. Persönlich kam ich aus dem Land von C/C++ und davor verfahrensbezogene Sprachen wie Fortran usw. Hier ist meine 2-minütige Überlegung, ähnliche Analoga im C++ - Paradigma zu finden.

Wenn ich einem C++/Java-Programmierer die Delegierten erklären würde, würde ich sagen

Was sind Delegierte? Dies sind statische Zeiger auf Klassen innerhalb einer anderen Klasse. Sobald Sie einen Zeiger zugewiesen haben, können Sie Funktionen/Methoden in dieser Klasse aufrufen. Daher werden einige Funktionen Ihrer Klasse "delegiert" (in C++ Welt - Zeiger auf durch einen Klassenobjektzeiger) an eine andere Klasse.

Was sind Protokolle? Konzeptionell dient es dem gleichen Zweck wie die Header-Datei der Klasse, die Sie als Delegate-Klasse zuweisen. Ein Protokoll ist eine explizite Methode, um zu definieren, welche Methoden in der Klasse implementiert werden müssen, deren Zeiger als Delegat in einer Klasse festgelegt wurde.

Wie kann ich etwas Ähnliches in C++ tun? Wenn Sie dies in C++ versuchen würden, würden Sie Zeiger auf Klassen (Objekte) in der Klassendefinition definieren und diese dann mit anderen Klassen verbinden, die zusätzliche Funktionen als Delegaten für Ihre Basisklasse bereitstellen. Diese Verkabelung muss jedoch innerhalb des Codes verwaltet werden und ist umständlich und fehleranfällig. Ziel C geht lediglich davon aus, dass Programmierer diese Regel nicht am besten einhalten können, und stellt Compiler-Einschränkungen bereit, um eine saubere Implementierung durchzusetzen.

10
DrBug

Schnelle Version

Ein Delegierter ist nur eine Klasse, die Arbeit für eine andere Klasse leistet. Lesen Sie den folgenden Code für ein etwas albernes (aber hoffentlich aufschlussreiches) Spielplatzbeispiel, das zeigt, wie dies in Swift gemacht wird.

// 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!"
}

In der Praxis werden Stellvertreter häufig in den folgenden Situationen eingesetzt

  1. Wenn eine Klasse Informationen an eine andere Klasse weitergeben muss
  2. Wenn eine Klasse einer anderen Klasse erlauben möchte, sie anzupassen

Die Klassen müssen vorher nichts voneinander wissen, außer dass die Delegate-Klasse dem erforderlichen Protokoll entspricht.

Ich empfehle dringend, die folgenden beiden Artikel zu lesen. Sie haben mir geholfen, die Delegierten noch besser zu verstehen als die Dokumentation .

9
Suragch

Okay, dies ist keine wirkliche Antwort auf die Frage, aber wenn Sie nachschlagen, wie Sie Ihren eigenen Delegierten dazu bringen können, könnte etwas weitaus Einfacheres eine bessere Antwort für Sie sein.

Ich setze meine Delegierten kaum um, weil ich sie selten brauche. Ich kann NUR EINEN Stellvertreter für ein Stellvertreterobjekt haben. Wenn Sie also möchten, dass Ihr Stellvertreter in eine Richtung kommuniziert oder Daten weitergibt, sind Sie mit Benachrichtigungen weitaus besser zurecht.

NSNotification kann Objekte an mehrere Empfänger übergeben und ist sehr einfach zu verwenden. Das funktioniert so:

Die Datei MyClass.m sollte so aussehen

#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

So verwenden Sie Ihre Benachrichtigung in anderen Klassen: Fügen Sie eine Klasse als Beobachter hinzu:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];

Implementieren Sie den Selektor:

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

Vergessen Sie nicht, Ihre Klasse als Beobachter zu entfernen, wenn

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
8
Tibidabo

nehmen wir an, Sie haben eine Klasse, die Sie entwickelt haben, und möchten eine Delegateigenschaft deklarieren, um sie benachrichtigen zu können, wenn ein Ereignis eintritt:

@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

sie deklarieren also ein Protokoll in der Headerdatei MyClass (oder einer separaten Headerdatei) und deklarieren die erforderlichen/optionalen Ereignishandler, die Ihr Delegat implementieren muss/sollte. Anschließend deklarieren Sie eine Eigenschaft in MyClass vom Typ ( id< MyClassDelegate>) Das heißt, jede Objective C-Klasse, die dem Protokoll MyClassDelegate entspricht. Sie werden feststellen, dass die Delegate-Eigenschaft als schwach deklariert ist. Dies ist sehr wichtig, um den Beibehaltungszyklus zu verhindern (meistens behält der Delegate sie bei) Die Instanz MyClass. Wenn Sie also den Delegaten als beibehalten deklariert haben, behalten beide sich gegenseitig bei, und keiner von beiden wird jemals freigegeben.

sie werden auch feststellen, dass die Protokollmethode die Instanz MyClass als Parameter an den Delegaten übergibt. Dies ist die beste Vorgehensweise, wenn der Delegat einige Methoden für die Instanz MyClass aufrufen möchte, und hilft auch, wenn der Delegat sich selbst deklariert als MyClassDelegate zu mehreren MyClass Instanzen, wie wenn Sie mehrere UITableView's Instanzen in Ihrem ViewController haben und sich für alle als UITableViewDelegate deklarieren.

und in Ihrem MyClass benachrichtigen Sie den Delegaten mit deklarierten Ereignissen wie folgt:

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

sie überprüfen zunächst, ob Ihr Delegat auf die Protokollmethode reagiert, die Sie aufrufen möchten, falls der Delegat sie nicht implementiert und die App dann abstürzt (auch wenn die Protokollmethode erforderlich ist).

8
m.eldehairy

Hier ist eine einfache Methode zum Erstellen von Delegaten

Erstellen Sie ein Protokoll in einer .h-Datei. Stellen Sie sicher, dass vor dem Protokoll mit @class gefolgt vom Namen des UIViewControllers < As the protocol I am going to use is UIViewController class>. definiert wurde.

Schritt: 1: Erstellen Sie ein neues Klassenprotokoll mit dem Namen "YourViewController", das die Unterklasse der UIViewController-Klasse darstellt, und weisen Sie diese Klasse dem zweiten ViewController zu.

Schritt: 2: Gehen Sie zur "YourViewController" -Datei und ändern Sie sie wie folgt:

#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

Die im Protokollverhalten definierten Methoden können mit @optional und @required im Rahmen der Protokolldefinition gesteuert werden.

Schritt: 3:Implementierung des Delegierten

    #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

// Teste, ob die Methode definiert wurde, bevor du sie aufrufst

 - (void) someMethodToCallDelegate {
     if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
           [self.delegate delegateMethodName:self]; 
     }
  }
7
Sujania

Um einen eigenen Delegaten zu erstellen, müssen Sie zunächst ein Protokoll erstellen und die erforderlichen Methoden deklarieren, ohne sie zu implementieren. Implementieren Sie dieses Protokoll anschließend in Ihre Headerklasse, in der Sie die Delegate- oder Delegate-Methoden implementieren möchten.

Ein Protokoll muss wie folgt deklariert werden:

@protocol ServiceResponceDelegate <NSObject>

- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;

@end

Dies ist die Serviceklasse, in der eine Aufgabe erledigt werden soll. Es wird gezeigt, wie Sie einen Delegaten definieren und den Delegaten festlegen. In der Implementierungsklasse werden nach Abschluss der Aufgabe die Methoden des Delegaten aufgerufen.

@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

Dies ist die Hauptansichtsklasse, von der aus die Serviceklasse aufgerufen wird, indem der Delegat auf sich selbst festgelegt wird. Und auch das Protokoll ist in der Header-Klasse implementiert.

@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}

- (void) go;

@end

@implementation viewController

//
//some methods
//

- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}

Das ist alles, und durch die Implementierung von Delegate-Methoden in dieser Klasse wird die Steuerung wiederhergestellt, sobald die Operation/Aufgabe abgeschlossen ist.

5
Mahesh

Haftungsausschluss: Dies ist die Swift-Version zum Erstellen einer delegate-Version.

Also, was sind Delegierte? … In der Softwareentwicklung gibt es allgemein wiederverwendbare Lösungsarchitekturen, mit deren Hilfe häufig auftretende Probleme in einem bestimmten Kontext gelöst werden können. Diese „Vorlagen“ werden sozusagen als Entwurfsmuster bezeichnet. Delegaten sind ein Entwurfsmuster, mit dem ein Objekt bei Eintreten eines bestimmten Ereignisses Nachrichten an ein anderes Objekt senden kann. Stellen Sie sich vor, ein Objekt A ruft ein Objekt B auf, um eine Aktion auszuführen. Sobald die Aktion abgeschlossen ist, sollte Objekt A wissen, dass B die Aufgabe abgeschlossen hat, und die erforderlichen Maßnahmen ergreifen. Dies kann mithilfe von Delegierten erreicht werden!

Zur besseren Erläuterung zeige ich Ihnen, wie Sie mit Swift in einer einfachen Anwendung einen benutzerdefinierten Delegaten erstellen, der Daten zwischen Klassen überträgt. Beginnen Sie, indem Sie dieses Startprojekt herunterladen oder klonen und ausführen es!

Sie können eine App mit zwei Klassen sehen, ViewController A und ViewController B. B hat zwei Ansichten, die beim Antippen die Hintergrundfarbe des ViewController ändern, nichts zu kompliziertes, oder? Lassen Sie uns nun auf einfache Weise darüber nachdenken, die Hintergrundfarbe von Klasse A auch zu ändern, wenn Sie auf die Ansichten von Klasse B tippen.

Das Problem ist, dass diese Ansichten Teil der Klasse B sind und keine Ahnung von Klasse A haben. Daher müssen wir einen Weg finden, um zwischen diesen beiden Klassen zu kommunizieren. Ich habe die Implementierung in 6 Schritte unterteilt, damit Sie sie bei Bedarf als Spickzettel verwenden können.

schritt 1: Suchen Sie nach der Pragma-Marke Schritt 1 in der ClassBVC-Datei und fügen Sie diese hinzu

//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}

Der erste Schritt besteht darin, ein protocol zu erstellen. In diesem Fall erstellen wir das Protokoll in Klasse B. Innerhalb des Protokolls können Sie so viele Funktionen erstellen, wie Sie möchten, basierend auf den Anforderungen Ihrer Implementierung. In diesem Fall haben wir nur eine einfache Funktion, die ein optionales UIColor als Argument akzeptiert. Es empfiehlt sich, Ihre Protokolle mit dem Wort delegate am Ende des Klassennamens zu benennen, in diesem Fall ClassBVCDelegate.

schritt 2: Suchen Sie in ClassVBC nach der Pragma-Marke Schritt 2 und fügen Sie diese hinzu

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

Hier erstellen wir nur eine Delegate-Eigenschaft für die Klasse. Diese Eigenschaft muss den Typ protocol annehmen und sollte optional sein. Fügen Sie außerdem das schwache Schlüsselwort vor der Eigenschaft ein, um Beibehaltungszyklen und potenzielle Speicherverluste zu vermeiden. Wenn Sie nicht wissen, was dies bedeutet, sorgen Sie sich jetzt nicht, denken Sie daran, dieses Schlüsselwort hinzuzufügen.

schritt 3: Suchen Sie nach der Pragma-Markierung Schritt 3 im Feld "handleTap method" in ClassBVC und fügen Sie diese hinzu

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

Eine Sache, die Sie wissen sollten, führen Sie die App aus und tippen Sie auf eine beliebige Ansicht, Sie werden kein neues Verhalten sehen und das ist richtig, aber ich möchte darauf hinweisen, dass die App nicht abstürzt, wenn der Delegierte angerufen wird, und Das liegt daran, dass wir es als optionalen Wert erstellen und deshalb nicht abstürzen, selbst wenn der Delegierte noch nicht existiert. Gehen wir jetzt zur Datei ClassAVC und machen Sie es, den Delegierten.

schritt 4: Suchen Sie in der handleTap-Methode in ClassAVC nach der Pragma-Markierung Schritt 4 und fügen Sie diese neben Ihrem Klassentyp hinzu.

//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}

Jetzt, da ClassAVC das ClassBVCDelegate-Protokoll übernommen hat, können Sie sehen, dass Ihr Compiler eine Fehlermeldung ausgibt, die besagt, dass der Typ 'ClassAVC' nicht dem Protokoll 'ClassBVCDelegate' entspricht, und dies bedeutet nur, dass Sie die Methoden des Protokolls noch nicht verwendet haben Wenn Klasse A das Protokoll annimmt, ist das wie das Unterzeichnen eines Vertrags mit Klasse B und dieser Vertrag sagt: "Jede Klasse, die mich adoptiert, MUSS meine Funktionen nutzen!"

Kurzer Hinweis: Wenn Sie aus einem Objective-C -Hintergrund stammen, denken Sie wahrscheinlich, dass Sie diesen Fehler auch unterbrechen können, indem Sie diese Methode optional machen. Zu meiner Überraschung und wahrscheinlich auch für Sie unterstützt die Sprache Swift keine optionale protocols, wenn Sie dies tun Dazu können Sie eine Erweiterung für protocol erstellen oder das Schlüsselwort @objc in Ihrer protocol-Implementierung verwenden.

Persönlich, wenn ich ein Protokoll mit verschiedenen optionalen Methoden erstellen muss, würde ich es lieber in verschiedene protocols aufteilen. Auf diese Weise folge ich dem Konzept, meinen Objekten eine einzige Verantwortung zuzuweisen, aber es kann abhängig von der spezifischen Implementierung variieren.

hier ist ein guter Artikel über optionale Methoden.

schritt 5: Suchen Sie nach der Pragma-Markierung Schritt 5 in der Methode zum Vorbereiten des Segues und fügen Sie diese hinzu

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

Hier erstellen wir nur eine Instanz von ClassBVC und weisen den Delegaten self zu, aber was ist self hier? na ja, ich bin der ClassAVC der delegiert wurde!

schritt 6: Suchen Sie abschließend das Pragma Schritt 6 in ClassAVC und verwenden Sie die Funktionen von protocol. Beginnen Sie mit der Eingabe von func changeBackgroundColor , und Sie werden sehen, dass dies der Fall ist Auto-Vervollständigung für Sie. Sie können eine beliebige Implementierung hinzufügen. In diesem Beispiel ändern wir nur die Hintergrundfarbe. Fügen Sie diese hinzu.

//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}

Jetzt starte die App!

Delegates gibt es überall und Sie verwenden sie wahrscheinlich auch ohne Vorankündigung. Wenn Sie in der Vergangenheit eine tableview -Delegation erstellt haben, arbeiten viele Klassen von UIKIT um sie herum und viele andere frameworks -Probleme. Sie lösen diese Hauptprobleme.

  • Vermeiden Sie festes Koppeln von Gegenständen.
  • Ändern Sie das Verhalten und die Darstellung, ohne Objekte zu unterklassifizieren.
  • Ermöglichen Sie die Bearbeitung von Aufgaben für beliebige Objekte.

Herzlichen Glückwunsch, Sie implementieren gerade einen benutzerdefinierten Delegaten. Ich weiß, dass Sie wahrscheinlich denken, dass es nur dafür so viel Ärger gibt. Nun, Delegation ist ein sehr wichtiges Entwurfsmuster, um zu verstehen, ob Sie ein iOS-Entwickler werden möchten, und denken Sie immer daran, dass es eine Eins-zu-eins-Beziehung zwischen Objekten gibt.

Sie können das ursprüngliche Tutorial sehen hier

3
James Rochabrun

Die Antwort ist tatsächlich beantwortet, aber ich möchte Ihnen einen "Spickzettel" zum Erstellen eines Delegaten geben:

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;

Methode:

-(void)delegateMEthod: (ArgType) arg{
}
2
Lal Krishna

Erstellen Sie aus meiner Sicht eine separate Klasse für diese Delegatmethode, und Sie können sie verwenden, wo Sie möchten.

in meiner benutzerdefinierten 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;

danach in.m Datei Array mit Objekten erstellen,

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

Hier werden alle für die benutzerdefinierte Delegatklasse festgelegt. Anschließend können Sie diese Delegatmethode verwenden, wo Sie möchten. Beispiel:.

in meinem anderen viewcontroller danach importieren

erstellen Sie die folgende Aktion zum Aufrufen der Delegatmethode

- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}

nach diesem Aufruf delegieren Methode wie folgt

- (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. Implementieren Sie die Methode in der Klasse .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);

}

0
Rohit Kashyap

Delegieren: - Erstellen

@protocol addToCartDelegate <NSObject>

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

@end

Senden und bitte delegieren, um anzuzeigen, dass Sie Daten senden

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

Beginnen wir mit einem Beispiel: Wenn wir ein Produkt online kaufen, durchläuft es einen Prozess wie Versand/Lieferung, der von verschiedenen Teams abgewickelt wird. Wenn der Versand abgeschlossen ist, sollte das Versandteam das Versandteam benachrichtigen und es sollte eine Eins-zu-Eins-Kommunikation zur Übertragung dieser Informationen sein Dies wäre ein Aufwand für andere Personen/Anbieter, die diese Informationen möglicherweise nur an erforderliche Personen weitergeben möchten.

Wenn wir also in Bezug auf unsere App denken, kann eine Veranstaltung eine Online-Bestellung sein und verschiedene Teams können wie mehrere Ansichten sein.

Hier ist der Code für ShippingView als Versandteam und DeliveryView als Versandteam:

//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