web-dev-qa-db-fra.com

Comment créer des délégués dans Objective-C?

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

Mais comment puis-je les créer?

733
Andy Jacobs

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 la méthode webViewDidStartLoad: de son délégué, 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é de UIWebView, il a probablement un code semblable à celui-ci pour voir si le délégué répond au message _webViewDidStartLoad:_ en utilisant respondsToSelector: et l'envoie si nécessaire.

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

La propriété delegate elle-même est généralement déclarée weak (dans ARC) ou assign (pré-ARC) pour éviter les boucles de retenue, car le délégué d'un objet détient 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.)

Faire des 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 le 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 elle crée un type spécial pour votre délégué, UIWebViewDelegate dans ce cas. Les responsables de la mise en œuvre délégués devraient adopter ce protocole:

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

Et puis implémenter les méthodes dans le protocole. Pour les méthodes déclarées dans le protocole en tant que _@optional_ (comme la plupart des méthodes déléguées), vous devez vérifier avec _-respondsToSelector:_ avant d'appeler une méthode particulière sur celle-ci.

Appellation

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 de délégation comme premier paramètre. Ils utilisent aussi souvent un formulaire de testament, de devoir ou de fait. Donc, _webViewDidStartLoad:_ (le premier paramètre est la vue Web) plutôt que loadStarted (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 par 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 de bits, 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, nous pouvons vérifier que notre délégué gère les messages en accédant à notre structure delegateRespondsTo, plutôt qu'en envoyant _-respondsToSelector:_ encore et encore.

Délégués informels

Avant que les protocoles n'existent, il était courant d'utiliser un catégorie sur NSObject pour déclarer les méthodes qu'un délégué pouvait implémenter. Par exemple, CALayer fait toujours ceci:

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

Cela indique essentiellement au compilateur que tout objet peut implémenter _displayLayer:_.

Vous utiliseriez alors la même approche _-respondsToSelector:_ comme décrit ci-dessus pour appeler cette méthode. Les délégués implémentent simplement cette méthode et attribuent la propriété delegate, 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 décrite ci-dessus, car elle pollue NSObject (ce qui rend la saisie semi-automatique moins utile) et empêche le compilateur de vous avertir des fautes de frappe et similaires. les erreurs.

875
Jesse Rusak

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 (ajoutez 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!");
}
377
Tibidabo

Lors de l'utilisation de la méthode du protocole formel pour créer le support des délégués, j'ai constaté que vous pouvez assurer une vérification de type appropriée (bien que l'exécution soit pas la 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'accesseur délégué (setDelegate). Cela aide à minimiser les erreurs.

18
umop

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 ont besoin d'un peu de temps pour s'y habituer - 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é dans NSWindow, mais que votre objet ne dispose que de mises en œuvre (méthodes) pour une ou plusieurs des nombreuses méthodes de délégation possibles. Il se passe donc quelque chose et NSWindow veut appeler votre objet. Il utilise simplement la méthode respondsToSelector d'Objective-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 le faire avec vos propres objets, il n’ya rien de spécial, vous pouvez par exemple avoir un NSArray de 27 objets, tous différents types d’objets, seuls 18 d’entre eux ayant la méthode -(void)setToBue; Les 9 autres non. Donc, appeler setToBlue sur tous 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.

17
Tom Andersen

S'il vous plaît! Consultez ci-dessous un didacticiel pas à pas pour comprendre le fonctionnement des délégués 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).
17
swiftBoy

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

& 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 suit:

@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é vos méthodes facultatives ou non.

15
Jean

Je pense que toutes ces réponses ont beaucoup de sens une fois que vous avez compris les délégués. Personnellement, je viens de C/C++ et, avant cela, des langages procéduraux tels que Fortran, etc., voici donc mon essai 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" (pointeur vers un monde en C++) à 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 connectez-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 mieux placés pour maintenir cette règle et fournit des restrictions au compilateur pour appliquer une mise en œuvre propre.

10
DrBug

Version rapide

Un délégué est simplement une classe qui travaille pour une autre classe. Lisez le code suivant pour un exemple de terrain de jeu quelque peu idiot (mais espérant être é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!"
}

En 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 au préalable, 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 .

9
Suragch

Ok, ce n’est pas vraiment une réponse à la question, mais si vous cherchez comment faire de votre propre délégué, peut-être que quelque chose de beaucoup plus simple pourrait être une meilleure réponse pour vous.

Je mets à peine en œuvre 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: Ajoutez une classe en tant qu'observateur:

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

Implémenter 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 retirer votre classe en tant qu'observateur si

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

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>) qui signifie toute classe Objective C conforme au protocole MyClassDelegate, vous remarquerez que la propriété delegate est déclarée comme étant faible, ceci est très important pour empêcher le cycle de conservation (le plus souvent le délégué conserve l’instance MyClass donc si vous déclarez le délégué comme retenu, les deux se conservent et aucun d’eux ne sera 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 dans le cas où le délégué souhaite appeler des méthodes sur l'instance MyClass et aide également lorsque le délégué se déclare comme MyClassDelegate à plusieurs instances MyClass, comme lorsque vous avez plusieurs UITableView's instances dans votre ViewController et se déclare comme UITableViewDelegate à toutes.

et à l'intérieur de votre MyClass, vous avertissez 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 se bloquerait alors (même si la méthode de protocole était requise).

8
m.eldehairy

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 < As the protocol I am going to use is UIViewController class>.

Step: 1: Créez une nouvelle classe Protocole nommé "YourViewController" qui sera la sous-classe de la classe UIViewController et affectez cette classe au second ViewController.

Step: 2: Allez dans le fichier "YourViewController" et modifiez-le 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:Implantation 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]; 
     }
  }
7
Sujania

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

C'est 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 reviendra une fois l'opération/la tâche terminée.

5
Mahesh

Avertissement: il s'agit de la version Swift de la création d'un delegate.

Alors, quels sont les délégués? … Dans le développement logiciel, il existe des architectures de solutions réutilisables générales qui aident à résoudre les problèmes courants dans un contexte donné, ces "modèles", pour ainsi dire, sont mieux connus sous le nom de modèles de conception. Les délégués sont un modèle de conception qui permet à un objet d'envoyer des messages à un autre objet lorsqu'un événement spécifique se produit. Imaginez un objet A appelle un objet B pour effectuer une action. Une fois que l'action est terminée, l'objet A doit savoir que B a terminé la tâche et prendre les mesures nécessaires. Cela peut être réalisé avec l'aide des délégués!

Pour une meilleure explication, je vais vous montrer comment créer un délégué personnalisé qui transmet les données entre les classes, avec Swift dans une application simple, commencez par télécharger ou cloner ce projet de démarrage et exécutez ça!

Vous pouvez voir une application avec deux classes, ViewController A et ViewController B. B a deux points de vue qui changent la couleur de fond du ViewController, rien de bien compliqué non? Eh bien, pensons maintenant de manière simple à modifier également la couleur de fond de la classe A lorsque les vues de la classe B sont exploitées.

Le problème, c’est que ces vues font partie de la classe B et n’ont aucune idée de la classe A. Nous devons donc trouver un moyen de communiquer entre ces deux classes et c’est là que la délégation se distingue. J'ai divisé la mise en œuvre en 6 étapes afin que vous puissiez l'utiliser comme aide-mémoire lorsque vous en avez besoin.

step 1: Recherchez le pragma mark step 1 dans le fichier ClassBVC et ajoutez-le.

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

La première étape consiste à créer un protocol. Dans ce cas, nous allons créer le protocole de classe B, dans lequel vous pouvez créer autant de fonctions que vous le souhaitez en fonction des exigences de votre implémentation. Dans ce cas, nous avons juste une fonction simple qui accepte un argument optionnel UIColor. Il est recommandé de nommer vos protocoles en ajoutant le mot delegate à la fin du nom de la classe, dans ce cas, ClassBVCDelegate.

step 2: Cherchez la marque de pragma step 2 dans ClassVBC et ajoutez ceci

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

Ici, nous venons de créer une propriété déléguée pour la classe. Cette propriété doit adopter le type protocol et elle devrait être facultative. En outre, vous devez ajouter le mot-clé faible avant la propriété pour éviter les cycles de conservation et les fuites de mémoire potentielles. Si vous ne savez pas ce que cela signifie, ne vous inquiétez pas pour l'instant, n'oubliez pas d'ajouter ce mot-clé.

step 3: Recherchez la marque de pragma step 3 à l'intérieur du handleTap method dans ClassBVC et ajoutez-le.

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

Une chose que vous devez savoir, exécutez l'application et appuyez sur n'importe quelle vue, vous ne verrez aucun nouveau comportement et c'est correct, mais ce que je veux souligner, c'est que l'application ne se bloque pas lorsque le délégué est appelé, et c'est parce que nous la créons comme une valeur facultative et c'est pourquoi elle ne plante pas même les délégués n'existent pas encore. Passons maintenant au fichier ClassAVC et transmettez-le, le délégué.

étape 4: Recherchez l'étape 4 de la marque de pragma dans la méthode handleTap dans ClassAVC et ajoutez-la à côté de votre type de classe.

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

Maintenant, ClassAVC a adopté le protocole ClassBVCDelegate, vous pouvez voir que votre compilateur vous donne une erreur indiquant que "Type" ClassAVC n'est pas conforme au protocole "ClassBVCDelegate", ce qui signifie simplement que vous n'avez pas utilisé les méthodes du protocole encore, imaginez que lorsque la classe A adopte le protocole, cela équivaut à signer un contrat avec la classe B et ce contrat stipule que "Toute classe qui m’adopte DOIT utiliser mes fonctions!

Remarque rapide: si vous venez d’un contexte Objective-C, vous pensez probablement que vous pouvez également taire cette erreur, ce qui rend cette méthode facultative, mais à ma grande surprise et probablement le vôtre, le langage Swift ne prend pas en charge l’option protocols, si vous voulez le faire, vous pouvez créer une extension pour votre protocol ou utiliser le mot clé @objc dans votre implémentation protocol.

Personnellement, si je dois créer un protocole avec différentes méthodes optionnelles, je préférerais le diviser en différentes protocols, ainsi je suivrai le concept de donner une seule responsabilité à mes objets, mais cela peut varier en fonction de la mise en œuvre spécifique.

voici un bon article sur les méthodes optionnelles.

étape 5: Recherchez l’étape 5 de la marque de pragma dans la méthode de préparation à la transition et ajoutez cette

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

Ici, nous créons juste une instance de ClassBVC et assignons son délégué à soi-même, mais qu'est-ce que soi ici? eh bien, le moi est la ClassAVC qui a été déléguée!

étape 6: Enfin, recherchez le pragma étape 6 dans ClassAVC et utilisons les fonctions de la protocol, commençons à taper func changeBackgroundColor et vous verrez que cela se termine automatiquement pour vous. Vous pouvez ajouter n'importe quelle implémentation à l'intérieur, dans cet exemple, nous allons simplement changer la couleur de fond, ajoutez ceci.

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

Maintenant, lancez l'application!

Delegates sont partout et vous les utiliserez probablement sans même préavis, si vous créez une tableview dans le passé, vous avez utilisé la délégation, de nombreuses classes de UIKIT fonctionnent autour d'eux et beaucoup d'autres frameworks aussi, ils résolvent ces problèmes principaux.

  • Évitez les couplages serrés d'objets.
  • Modifiez le comportement et l'apparence sans avoir besoin de sous-classe d'objets.
  • Autoriser les tâches à être gérées vers n'importe quel objet arbitraire.

Félicitations, vous venez de mettre en place un délégué personnalisé, je sais que vous pensez probablement tant de problèmes juste pour cela? Eh bien, la délégation est un modèle de conception très important à comprendre si vous souhaitez devenir un développeur iOS et gardez toujours à l’esprit qu’ils entretiennent une relation un à un entre les objets.

Vous pouvez voir le tutoriel original ici

3
James Rochabrun

La réponse est en fait une réponse, mais j'aimerais vous donner un "aide-mémoire" pour la création d'un délégué:

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;

Méthode:

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

De mon point de vue, créez une classe séparée pour cette méthode de délégation et vous pouvez utiliser où vous voulez.

dans mon 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;

après que le fichier in.m crée un tableau avec des objets,

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

Ici, tous sont définis pour la classe déléguée personnalisée.après, vous pouvez utiliser cette méthode de délégué à votre guise. Par exemple ...

dans mon autre importation viewcontroller après cela

créer une action pour appeler une méthode de délégué comme celle-ci

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

après cette méthode d'appel délégué comme celui-ci

- (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. Implémentez la méthode dans la classe .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);

}

0
Rohit Kashyap

Délégué: - Créer

@protocol addToCartDelegate <NSObject>

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

@end

Envoyer et assigner un délégué pour voir si vous envoyez des données

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

Commençons par un exemple. Si nous achetons un produit en ligne, il suivra un processus d'expédition/livraison géré par différentes équipes. serait une surcharge pour d’autres personnes/le fournisseur pourrait vouloir transmettre cette information uniquement aux personnes requises.

Donc, si nous pensons en termes de notre application, un événement peut être une commande en ligne et différentes équipes peuvent être comme de multiples points de vue.

Voici le code considérer ShippingView comme équipe d'expédition & DeliveryView comme équipe de livraison:

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