Question

Je sais comment fonctionnent les délégués et comment les utiliser.

Mais comment puis-je les créer?

Était-ce utile?

La solution

Un délégué Objective-C est un objet auquel un autre objet a été affecté à la propriété delegate. Pour en créer un, il vous suffit de définir une classe qui implémente les méthodes de délégation qui vous intéressent et de marquer cette classe comme implémentant le protocole de délégué.

Par exemple, supposons que vous ayez un UIWebView. Si vous souhaitez implémenter le délégué webViewDidStartLoad: , vous pouvez créer une classe comme celle-ci:

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

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

Vous pouvez ensuite créer une instance de MyClass et l'affecter en tant que délégué de la vue Web:

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

Du côté respondsToSelector:, il a probablement un code similaire à celui-ci pour voir si le délégué répond au message weak en utilisant assign et envoyez-le le cas échéant.

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

La propriété delegate elle-même est généralement déclarée UIWebViewDelegate (dans ARC) ou @optional (pré-ARC) pour éviter les boucles de retenue, car le délégué d'un objet contient souvent une référence forte à cet objet. (Par exemple, un contrôleur de vue est souvent le délégué d'une vue qu'il contient.)

Création de délégués pour vos classes

Pour définir vos propres délégués, vous devez déclarer leurs méthodes quelque part, comme indiqué dans la section Apple Docs sur les protocoles . Vous déclarez généralement un protocole formel. La déclaration, paraphrasée à partir de UIWebView.h, ressemblerait à ceci:

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

Ceci est analogue à une classe d'interface ou de base abstraite, car cela crée un type spécial pour votre délégué, -respondsToSelector: dans ce cas. Les responsables de la mise en œuvre délégués devraient adopter ce protocole:

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

Et implémentez ensuite les méthodes du protocole. Pour les méthodes déclarées dans le protocole comme loadStarted (comme la plupart des méthodes déléguées), vous devez vérifier auprès de delegateRespondsTo avant d'appeler une méthode particulière sur celui-ci.

Nommage

Les méthodes de délégation sont généralement nommées en commençant par le nom de la classe de délégation et prennent l'objet en tant que premier paramètre. Ils utilisent aussi souvent un formulaire de testament, de devoir ou de fait. Ainsi, NSObject (le premier paramètre est la vue Web) plutôt que CALayer (ne prenant aucun paramètre) par exemple.

Optimisations de vitesse

Au lieu de vérifier si un délégué répond à un sélecteur chaque fois que nous souhaitons l'envoyer un message, vous pouvez mettre en cache ces informations lorsque les délégués sont définis. Une méthode très simple consiste à utiliser un champ binaire, comme suit:

@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

Ensuite, dans le corps du message, nous pouvons vérifier que notre délégué gère les messages en accédant à notre structure displayLayer: plutôt qu'en envoyant plusieurs fois <=>.

Délégués informels

Avant que les protocoles n'existent, il était courant d'utiliser un category sur <=> pour déclarer les méthodes qu'un délégué pourrait implémenter. Par exemple, <=> fait toujours ceci:

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

Ceci indique essentiellement au compilateur que tout objet peut implémenter <=>.

Vous utiliseriez alors la même <=> approche que celle décrite ci-dessus pour appeler cette méthode. Les délégués implémentent simplement cette méthode et attribuent la propriété <=>, et le tour est joué (rien ne permet de déclarer que vous vous conformez à un protocole). Cette méthode est courante dans les bibliothèques d’Apple, mais le nouveau code devrait utiliser l’approche de protocole la plus moderne ci-dessus, car elle pollue <=> (ce qui rend la complétion automatique moins utile) et empêche le compilateur de vous avertir des fautes de frappe et autres erreurs similaires.

Autres conseils

La réponse approuvée est excellente, mais si vous recherchez une réponse d'une minute, essayez ceci:

Le fichier MyClass.h devrait ressembler à ceci (ajouter des lignes de délégué avec des commentaires!)

#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

Le fichier MyClass.m devrait ressembler à ceci

#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

Pour utiliser votre délégué dans une autre classe (UIViewController appelé MyVC dans ce cas) 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

Implémenter la méthode déléguée

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

Lors de l'utilisation de la méthode protocolaire formelle pour la création d'un support délégué, nous avons constaté que vous pouvez assurer une vérification de type correcte (bien que l'exécution, pas le temps de compilation) en ajoutant quelque chose comme:

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

dans votre code d'accès délégué (setDelegate). Cela aide à minimiser les erreurs.

C’est peut-être plus dans le sens de ce qui vous manque:

Si vous venez d'un point de vue semblable à C ++, les délégués doivent s'habituer un peu - mais en gros, "ils travaillent".

La façon dont cela fonctionne est que vous définissez un objet que vous avez écrit en tant que délégué de NSWindow, mais que votre objet ne possède que des implémentations (méthodes) pour une ou plusieurs des nombreuses méthodes de délégation possibles. Il se passe donc quelque chose et NSWindow souhaite appeler votre objet. Il utilise simplement la méthode respondsToSelector d'Object-c pour déterminer si votre objet souhaite que cette méthode soit appelée, puis l'appelle. C’est ainsi que fonctionne object-c - les méthodes sont recherchées à la demande.

C’est totalement trivial de faire cela avec vos propres objets, il n’ya rien de spécial, vous pourriez par exemple avoir un NSArray de 27 objets, tous différents types d’objets, seulement 18 eux ayant la méthode - (void) setToBue; Les 9 autres ne le font pas. Donc, pour appeler setToBlue sur les 18 qui en ont besoin, quelque chose comme ceci:

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

L'autre chose à propos des délégués est qu'ils ne sont pas conservés. Vous devez donc toujours définir le délégué sur nil dans votre méthode MyClass dealloc .

S'il vous plaît! Consultez le didacticiel pas à pas ci-dessous pour comprendre le fonctionnement de Delegates dans iOS.

  

Délégué sous iOS

J'ai créé deux ViewControllers (pour envoyer des données de l'un à l'autre)

  1. FirstViewController implémente un délégué (qui fournit des données).
  2. SecondViewController déclare le délégué (qui recevra les données).

En tant que bonne pratique recommandée par Apple, il est bon que le délégué (qui est un protocole, par définition) se conforme au protocole NSObject .

@protocol MyDelegate <NSObject>
    ...
@end

& amp; pour créer des méthodes optionnelles au sein de votre délégué (c'est-à-dire des méthodes qui ne doivent pas nécessairement être implémentées), vous pouvez utiliser l'annotation @optional comme ceci:

@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

Ainsi, lorsque vous utilisez des méthodes que vous avez spécifiées comme facultatives, vous devez (dans votre classe) vérifier avec respondsToSelector si la vue (conforme à votre délégué) a réellement implémenté votre méthode facultative ( s) ou pas.

Je pense que toutes ces réponses ont beaucoup de sens une fois que vous comprenez les délégués. Personnellement, je suis originaire de C / C ++ et, avant cela, de langages procéduraux tels que Fortran, etc., voici donc mon résumé de 2 minutes sur la recherche d'analogues similaires dans le paradigme C ++.

Si je devais expliquer les délégués à un programmeur C ++ / Java, je dirais

Que sont les délégués? Ce sont des pointeurs statiques vers des classes d'une autre classe. Une fois que vous avez affecté un pointeur, vous pouvez appeler des fonctions / méthodes dans cette classe. Par conséquent, certaines fonctions de votre classe sont "déléguées". (En monde C ++ - pointeur sur un pointeur d'objet de classe) vers une autre classe.

Que sont les protocoles? Conceptuellement, il a la même fonction que le fichier d’en-tête de la classe que vous assignez en tant que classe déléguée. Un protocole est un moyen explicite de définir les méthodes à implémenter dans la classe dont le pointeur a été défini en tant que délégué dans une classe.

Comment puis-je faire quelque chose de similaire en C ++? Si vous avez essayé de le faire en C ++, définissez les pointeurs sur les classes (objets) dans la définition de classe, puis reliez-les à d'autres classes qui fourniront des fonctions supplémentaires en tant que délégués de votre classe de base. Mais ce câblage doit être conservé dans le code et sera maladroit et sujet aux erreurs. Objective C suppose simplement que les programmeurs ne sont pas les meilleurs pour maintenir cette règle et fournit des restrictions au compilateur pour appliquer une mise en œuvre propre.

Version Swift

Un délégué est simplement une classe qui travaille pour une autre classe. Lisez le code suivant pour consulter un exemple de terrain de jeu quelque peu idiot (mais néanmoins éclairant) qui montre comment procéder dans Swift.

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

Dans la pratique, les délégués sont souvent utilisés dans les situations suivantes

  1. Quand une classe a besoin de communiquer des informations à une autre classe
  2. Quand une classe veut permettre à une autre classe de la personnaliser

Les classes n'ont pas besoin de savoir quoi que ce soit les unes des autres à l'avance, sauf que la classe déléguée est conforme au protocole requis.

Je recommande fortement de lire les deux articles suivants. Ils m'ont aidé à comprendre les délégués encore mieux que le documentation fait.

D'accord, ce n'est pas vraiment une réponse à la question, mais si vous envisagez de nommer votre propre délégué, une solution beaucoup plus simple pourrait peut-être être une meilleure réponse pour vous.

Je mets en place à peine mes délégués car j'en ai rarement besoin. Je peux avoir UN SEUL délégué pour un objet délégué. Donc, si vous souhaitez que votre délégué communique / transmette des données dans un sens, il est préférable de le faire avec des notifications.

NSNotification peut transmettre des objets à plusieurs destinataires et il est très facile à utiliser. Cela fonctionne comme ceci:

Le fichier MyClass.m devrait ressembler à ceci

#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

Pour utiliser votre notification dans d'autres classes: Ajouter une classe en tant qu'observateur:

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

Implémentez le sélecteur:

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

N'oubliez pas de supprimer votre classe en tant qu'observateur si

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

Disons que vous avez une classe que vous avez développée et que vous voulez déclarer une propriété de délégué pour pouvoir la notifier lorsqu'un événement se produit:

@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

vous déclarez donc un protocole dans le fichier d’en-tête MyClass (ou un fichier d’en-tête séparé), et déclarez les gestionnaires d’événements obligatoires / facultatifs que votre délégué doit / doit implémenter, puis déclarez une propriété dans MyClass de type ( id < MyClassDelegate > ), ce qui signifie toute classe d'objectif c conforme au protocole MyClassDelegate , vous remarquerez que la propriété déléguée est déclaré comme faible, il est très important d’empêcher le cycle de conservation (le délégué conserve le plus souvent l’instance MyClass ; ainsi, si vous déclarez le délégué comme étant retenu, les deux ne se conservent pas et aucun être libéré).

vous remarquerez également que les méthodes de protocole transmettent l'instance MyClass au délégué en tant que paramètre. Cette pratique est recommandée si le délégué souhaite appeler des méthodes sur MyClass . instance et aide également lorsque le délégué se déclare en tant que MyClassDelegate vers plusieurs instances MyClass , comme lorsque vous avez plusieurs instances de UITableView dans votre ViewController et se déclare en tant que UITableViewDelegate pour tous.

et dans votre MyClass , vous notifiez le délégué avec les événements déclarés comme suit:

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

vous devez d’abord vérifier si votre délégué répond à la méthode de protocole que vous êtes sur le point d’appeler au cas où le délégué ne l’implémenterait pas et que l’application planterait alors (même si la méthode de protocole était requise).

Voici une méthode simple pour créer des délégués

Créer un protocole dans un fichier .h. Assurez-vous que cela est défini avant le protocole en utilisant @class suivi du nom de UIViewController < Le protocole que je vais utiliser est la classe UIViewController >.

Étape: 1: créer un nouveau protocole de classe nommé "YourViewController". qui sera la sous-classe de la classe UIViewController et affectera cette classe au second ViewController.

Étape 2: sélectionnez l'option "YourViewController". fichier et le modifier comme suit:

#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

Les méthodes définies dans le comportement du protocole peuvent être contrôlées avec @optional et @ requis dans le cadre de la définition du protocole.

Étape 3: Mise en œuvre du délégué

    #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 si la méthode a été définie avant de l'appeler

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

Pour créer votre propre délégué, vous devez d’abord créer un protocole et déclarer les méthodes nécessaires, sans implémentation. Et puis implémentez ce protocole dans votre classe d’en-tête où vous souhaitez implémenter le délégué ou les méthodes déléguées.

Un protocole doit être déclaré comme suit:

@protocol ServiceResponceDelegate <NSObject>

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

@end

Il s'agit de la classe de service où une tâche doit être effectuée. Il montre comment définir un délégué et comment définir le délégué. Une fois la tâche terminée, les méthodes du délégué sont appelées dans la classe d'implémentation.

@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

Il s'agit de la classe de vue principale à partir de laquelle la classe de service est appelée en définissant le délégué sur elle-même. Et aussi le protocole est implémenté dans la classe d’en-tête.

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

- (void) go;

@end

@implementation viewController

//
//some methods
//

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

Voilà, et en implémentant des méthodes de délégation dans cette classe, le contrôle sera rétabli une fois l'opération / la tâche effectuée.

Disclaimer: this is the Swift version of how to create a delegate.

So, what are delegates? …in software development, there are general reusable solution architectures that help to solve commonly occurring problems within a given context, these “templates”, so to speak, are best known as design patterns. Delegates are a design pattern that allows one object to send messages to another object when a specific event happens. Imagine an object A calls an object B to perform an action. Once the action is complete, object A should know that B has completed the task and take necessary action, this can be achieved with the help of delegates!

For a better explanation, I am going to show you how to create a custom delegate that passes data between classes, with Swift in a simple application,start by downloading or cloning this starter project and run it!

You can see an app with two classes, ViewController A and ViewController B. B has two views that on tap changes the background color of the ViewController, nothing too complicated right? well now let’s think in an easy way to also change the background color of class A when the views on class B are tapped.

The problem is that this views are part of class B and have no idea about class A, so we need to find a way to communicate between this two classes, and that’s where delegation shines. I divided the implementation into 6 steps so you can use this as a cheat sheet when you need it.

step 1: Look for the pragma mark step 1 in ClassBVC file and add this

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

The first step is to create a protocol, in this case, we will create the protocol in class B, inside the protocol you can create as many functions that you want based on the requirements of your implementation. In this case, we just have one simple function that accepts an optional UIColor as an argument. Is a good practice to name your protocols adding the word delegate at the end of the class name, in this case, ClassBVCDelegate.

step 2: Look for the pragma mark step 2 in ClassVBC and add this

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

Here we just create a delegate property for the class, this property must adopt the protocol type, and it should be optional. Also, you should add the weak keyword before the property to avoid retain cycles and potential memory leaks, if you don’t know what that means don’t worry for now, just remember to add this keyword.

step 3: Look for the pragma mark step 3 inside the handleTap method in ClassBVC and add this

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

One thing that you should know, run the app and tap on any view, you won’t see any new behavior and that’s correct but the thing that I want to point out is that the app it’s not crashing when the delegate is called, and it’s because we create it as an optional value and that’s why it won’t crash even the delegated doesn’t exist yet. Let’s now go to ClassAVC file and make it, the delegated.

step 4: Look for the pragma mark step 4 inside the handleTap method in ClassAVC and add this next to your class type like this.

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

Now ClassAVC adopted the ClassBVCDelegate protocol, you can see that your compiler is giving you an error that says “Type ‘ClassAVC does not conform to protocol ‘ClassBVCDelegate’ and this only means that you didn’t use the methods of the protocol yet, imagine that when class A adopts the protocol is like signing a contract with class B and this contract says “Any class adopting me MUST use my functions!”

Quick note: If you come from an Objective-C background you are probably thinking that you can also shut up that error making that method optional, but for my surprise, and probably yours, Swift language does not support optional protocols, if you want to do it you can create an extension for your protocol or use the @objc keyword in your protocol implementation.

Personally, If I have to create a protocol with different optional methods I would prefer to break it into different protocols, that way I will follow the concept of giving one single responsibility to my objects, but it can vary based on the specific implementation.

here is a good article about optional methods.

step 5: Look for the pragma mark step 5 inside the prepare for segue method and add this

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

Here we are just creating an instance of ClassBVC and assign its delegate to self, but what is self here? well, self is the ClassAVC which has been delegated!

step 6: Finally, look for the pragma step 6 in ClassAVC and let’s use the functions of the protocol, start typing func changeBackgroundColor and you will see that it’s auto-completing it for you. You can add any implementation inside it, in this example, we will just change the background color, add this.

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

Now run the app!

Delegates are everywhere and you probably use them without even notice, if you create a tableview in the past you used delegation, many classes of UIKIT works around them and many other frameworks too, they solve these main problems.

  • Avoid tight coupling of objects.
  • Modify behavior and appearance without the need to subclass objects.
  • Allow tasks to be handled off to any arbitrary object.

Congratulations, you just implement a custom delegate, I know that you are probably thinking, so much trouble just for this? well, delegation is a very important design pattern to understand if you want to become an iOS developer, and always keep in mind that they have one to one relationship between objects.

You can see the original tutorial here

Answer is actually answered, but I would like to give you a "cheat sheet" for creating a delegate:

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;

Method:

-(void)delegateMEthod: (ArgType) arg{
}

In my point of view create separate class for that delegate method and you can use where you want.

in my Custom 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;

after that in.m file create array with objects,

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

Here all are set for Custom delegate class.after that you can use this delegate method where you want.for example...

in my another viewcontroller import after that

create action for calling delegate method like this

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

after that call delegate method like this

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

Delegate :- Create

@protocol addToCartDelegate <NSObject>

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

@end

Send and please assign delegate to view you are sending data

[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. Implement the method in the class .m -(void)didRemoveCellWithTag:(NSInteger)tag { NSLog@("Tag %d",tag);

}

Let's start with an example , if we buy a product online ,it goes through process like shipping/delivery handled by different teams.So if shipping gets completed ,shipping team should notify delivery team & it should be one to one communication as broadcasting this information would be overhead for other people / vendor might want to pass this information only to required people.

So if we think in terms of our app, an event can be an online order & different teams can be like multiple views.

Here is code consider ShippingView as Shipping team & DeliveryView as 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
        //
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top