Je sais comment les délégués travaillent et je sais comment je peux les utiliser.
Mais comment les créer?
Je sais comment les délégués travaillent et je sais comment je peux les utiliser.
Mais comment les créer?
Réponses:
Un délégué Objective-C est un objet qui a été affecté à la delegate
propriété un autre objet. Pour en créer une, vous définissez une classe qui implémente les méthodes déléguées qui vous intéressent et marquez cette classe comme implémentant le protocole délégué.
Par exemple, supposons que vous ayez un UIWebView
. Si vous souhaitez implémenter la webViewDidStartLoad:
méthode 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
Ensuite, vous pouvez 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;
Sur le UIWebView
côté, il a probablement un code similaire à celui-ci pour voir si le délégué répond au webViewDidStartLoad:
message en utilisant respondsToSelector:
et l'envoyer le cas échéant.
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
La propriété déléguée elle-même est généralement déclarée weak
(dans ARC) ou assign
(pré-ARC) pour éviter de conserver les boucles, 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.)
Pour définir vos propres délégués, vous devrez déclarer leurs méthodes quelque part, comme indiqué dans les documents Apple sur les protocoles . Vous déclarez généralement un protocole formel. La déclaration, paraphrasée de UIWebView.h, ressemblerait à ceci:
@protocol UIWebViewDelegate <NSObject>
@optional
- (void)webViewDidStartLoad:(UIWebView *)webView;
// ... other methods here
@end
Ceci est analogue à une interface ou à une classe de base abstraite, car elle crée un type spécial pour votre délégué, UIWebViewDelegate
dans ce cas. Les exécutants délégués devraient adopter ce protocole:
@interface MyClass <UIWebViewDelegate>
// ...
@end
Et puis implémentez les méthodes dans le protocole. Pour les méthodes déclarées dans le protocole comme @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 dessus.
Les méthodes déléguées sont généralement nommées en commençant par le nom de la classe délégante et prennent l'objet délégué comme premier paramètre. Ils utilisent aussi souvent un testament, un devoir ou un didacticiel. Ainsi, webViewDidStartLoad:
(le premier paramètre est la vue Web) plutôt que loadStarted
(en ne prenant aucun paramètre) par exemple.
Au lieu de vérifier si un délégué répond à un sélecteur chaque fois que nous voulons lui envoyer un message, vous pouvez mettre en cache ces informations lorsque les délégués sont définis. Une façon très simple de le faire est d'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 delegateRespondsTo
structure, plutôt qu'en envoyant -respondsToSelector:
encore et encore.
Avant l'existence des protocoles, il était courant d'utiliser une catégorie sur NSObject
pour déclarer les méthodes qu'un délégué pouvait implémenter. Par exemple, fait CALayer
toujours ceci:
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
Cela indique au compilateur que tout objet peut implémenter displayLayer:
.
Vous utiliseriez alors la même -respondsToSelector:
approche que celle décrite ci-dessus pour appeler cette méthode. Les délégués implémentent cette méthode et assignent la delegate
propriété, et c'est tout (il n'y a pas de déclaration de conformité à un protocole). Cette méthode est courante dans les bibliothèques d'Apple, mais le nouveau code devrait utiliser l'approche de protocole plus moderne ci-dessus, car cette approche pollue NSObject
(ce qui rend la saisie semi-automatique moins utile) et rend difficile pour le compilateur de vous avertir des fautes de frappe et des erreurs similaires.
unsigned int
type en BOOL
tant que la valeur de retour de delegate respondsToSelector
est de type BOOL
.
La réponse approuvée est excellente, mais si vous cherchez 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!");
}
myClass
instancié dans MyVC.m?
Lors de l'utilisation de la méthode de protocole formelle pour créer la prise en charge des délégués, j'ai constaté que vous pouvez garantir une vérification de type appropriée (bien que, au moment de l'exécution, pas de 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'accesseur délégué (setDelegate). Cela permet de minimiser les erreurs.
S'il vous plaît! consultez le didacticiel simple étape par étape ci-dessous pour comprendre le fonctionnement des délégués dans iOS.
J'ai créé deux ViewControllers (pour envoyer des données de l'un à l'autre)
C'est peut-être plus dans le sens de ce qui vous manque:
Si vous venez d'un point de vue similaire à C ++, les délégués prennent un peu de temps pour s'y habituer - mais en gros 'ils fonctionnent juste'.
La façon dont cela fonctionne est que vous définissez un objet que vous avez écrit en tant que délégué à NSWindow, mais votre objet n'a que des implémentations (méthodes) pour une ou quelques-unes des nombreuses méthodes de délégué possibles. Donc, quelque chose se passe et NSWindow
veut appeler votre objet - il utilise simplement la méthode d'Objective-c respondsToSelector
pour déterminer si votre objet veut que cette méthode soit appelée, puis l'appelle. Voici comment fonctionne objective-c - les méthodes sont recherchées à la demande.
C'est totalement trivial de le faire avec vos propres objets, il n'y a rien de spécial, vous pouvez par exemple avoir un NSArray
des 27 objets, toutes sortes d'objets, seulement 18 certains ayant la méthode -(void)setToBue;
Les 9 autres n'en ont pas. Donc, pour appeler setToBlue
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é nil
dans votre MyClass dealloc
méthode.
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 NSObject
protocole.
@protocol MyDelegate <NSObject>
...
@end
& pour créer des méthodes facultatives 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' @optional
annotation 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 respondsToSelector
si la vue (conforme à votre délégué) a réellement mis en œuvre votre ou vos méthodes facultatives.
Je pense que toutes ces réponses ont beaucoup de sens une fois que vous comprenez les délégués. Personnellement, je viens du pays du C / C ++ et avant cela, des langages procéduraux comme Fortran, etc. voici donc mon avis 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» (dans le monde C ++ - pointeur vers par un pointeur d'objet de classe) vers une autre classe.
Quels sont les protocoles? Sur le plan conceptuel, il sert un objectif similaire au fichier d'en-tête de la classe que vous affectez en tant que classe déléguée. Un protocole est un moyen explicite de définir quelles méthodes doivent être implémentées dans la classe dont le pointeur a été défini comme délégué au sein d'une classe.
Comment puis-je faire quelque chose de similaire en C ++? Si vous avez essayé de le faire en C ++, vous le feriez en définissant des pointeurs vers des classes (objets) dans la définition de classe, puis en les câblant à d'autres classes qui fourniront des fonctions supplémentaires en tant que délégués à votre classe de base. Mais ce câblage doit être maintenu 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 discipline et fournit des restrictions de compilation pour appliquer une implémentation propre.
Un délégué n'est qu'une classe qui travaille pour une autre classe. Lisez le code suivant pour un exemple de Playground quelque peu stupide (mais avec un peu de chance) qui montre comment cela est fait 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
Les classes n'ont pas besoin de se connaître 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é à mieux comprendre les délégués que la documentation .
D'accord, ce n'est pas vraiment une réponse à la question, mais si vous cherchez à faire votre propre délégué, peut-être que quelque chose de beaucoup plus simple pourrait être une meilleure réponse pour vous.
J'implémente à peine mes délégués car j'en ai rarement besoin. Je ne peux avoir qu'UN délégué pour un objet délégué. Donc, si vous voulez que votre délégué communique ou transmette des données à sens unique, vous êtes bien meilleur avec les 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 une autre classe: Ajoutez 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 retirer 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 souhaitez déclarer une propriété déléguée 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 MyClass
fichier d' en- tête (ou un fichier d'en-tête séparé), déclarez les gestionnaires d'événements requis / facultatifs que votre délégué doit / devrait implémenter, puis déclarez une propriété dans MyClass
de type ( id< MyClassDelegate>
) qui signifie toute classe c objective conforme à le protocole MyClassDelegate
, vous remarquerez que la propriété delegate est déclarée faible, ceci est très important pour empêcher le cycle de conservation (le plus souvent, le délégué conserve l' MyClass
instance donc si vous avez déclaré le délégué comme retenue, les deux se conserveront et aucun d'entre eux seront jamais publiés).
vous remarquerez également que les méthodes de protocole transmettent l' MyClass
instance au délégué en tant que paramètre, c'est la meilleure pratique dans le cas où le délégué souhaite appeler certaines méthodes sur l' MyClass
instance et aide également lorsque le délégué se déclare quant MyClassDelegate
à plusieurs MyClass
instances, comme lorsque vous en avez plusieurs UITableView's
instances dans votre ViewController
et se déclare comme un UITableViewDelegate
à tous.
et à l'intérieur de 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 vérifiez d'abord 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 l'application se bloquerait alors (même si la méthode de protocole est requise).
Voici une méthode simple pour créer des délégués
Créez le protocole dans le fichier .h. Assurez-vous qu'il est défini avant le protocole à l'aide de @class suivi du nom de UIViewController< As the protocol I am going to use is UIViewController class>.
Étape: 1: Créez un nouveau protocole de classe nommé "YourViewController" qui sera la sous-classe de la classe UIViewController et affectez cette classe au deuxième ViewController.
Étape: 2: Accédez au fichier "YourViewController" et modifiez-le comme ci-dessous:
#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 @required 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émenter. 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 de délégué.
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é. Dans la classe d'implémentation, une fois la tâche terminée, les méthodes du délégué sont appelées.
@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 lui-même. Et le protocole est également 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];
}
C'est tout, et en implémentant des méthodes déléguées dans cette classe, le contrôle reviendra une fois l'opération / tâche terminée.
Avertissement: il s'agit de la Swift
version de la création d'un fichier delegate
.
Alors, quels sont les délégués? … Dans le développement de logiciels, il existe des architectures de solutions générales réutilisables 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 l'action 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 passe des 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-le!
Vous pouvez voir une application avec deux classes, ViewController A
et ViewController B
. B a deux vues qui au toucher modifient la couleur d'arrière-plan du ViewController
, rien de trop compliqué non? Eh bien, réfléchissons maintenant de manière simple à la couleur d'arrière-plan de la classe A lorsque les vues sur la classe B sont exploitées.
Le problème 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 brille. J'ai divisé l'implémentation en 6 étapes afin que vous puissiez l'utiliser comme une feuille de triche lorsque vous en avez besoin.
étape 1: recherchez la marque pragma étape 1 dans le fichier ClassBVC et ajoutez-la
//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 en classe B, à l'intérieur du protocole, 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 une option UIColor
comme argument. Est une bonne pratique pour nommer vos protocoles en ajoutant le mot delegate
à la fin du nom de la classe, dans ce cas ClassBVCDelegate
,.
étape 2: recherchez la marque pragma étape 2 ClassVBC
et ajoutez-la
//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 protocol
type et elle doit être facultative. En outre, vous devez ajouter le mot clé faible avant la propriété pour éviter de conserver les cycles et les fuites de mémoire potentielles.Si vous ne savez pas ce que cela signifie, ne vous inquiétez pas pour le moment, n'oubliez pas d'ajouter ce mot clé.
Étape 3: Recherchez la marque pragma étape 3 à l' intérieur du handleTap method
dans ClassBVC
et ajoutez cette
//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 la chose que je veux souligner est que l'application ne se bloque pas lorsque le délégué est appelé, et c'est parce que nous le créons en tant que valeur facultative et c'est pourquoi il ne plantera pas même le délégué n'existe pas encore. Allons maintenant au ClassAVC
fichier et le faire, le délégué.
étape 4: recherchez la marque de pragma étape 4 dans la méthode handleTap ClassAVC
et ajoutez-la à côté de votre type de classe comme ceci.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
Maintenant ClassAVC a adopté le ClassBVCDelegate
protocole, vous pouvez voir que votre compilateur vous donne une erreur qui dit "Type" ClassAVC n'est pas conforme au protocole "ClassBVCDelegate" et cela signifie seulement que vous n'avez pas encore utilisé les méthodes du protocole, imaginez que quand la classe A adopte le protocole, c'est comme signer un contrat avec la classe B et ce contrat dit "Toute classe qui m'adopte DOIT utiliser mes fonctions!"
Remarque rapide: si vous venez d'un Objective-C
arrière-plan, vous pensez probablement que vous pouvez également fermer cette erreur en rendant cette méthode facultative, mais à ma grande surprise, et probablement la vôtre, le Swift
langage ne prend pas en charge facultatif protocols
, si vous voulez le faire, vous pouvez créer une extension pour votre protocol
ou utilisez le mot clé @objc dans votre protocol
implémentation.
Personnellement, si je dois créer un protocole avec différentes méthodes optionnelles, je préférerais le diviser en différents protocols
, de cette façon je suivrai le concept de donner une seule responsabilité à mes objets, mais cela peut varier en fonction de l'implémentation spécifique.
voici un bon article sur les méthodes optionnelles.
étape 5: recherchez la marque de pragma étape 5 à l'intérieur de la méthode de préparation à la séquence et ajoutez-la
//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 simplement une instance de ClassBVC
et affectons son délégué à soi, mais qu'est-ce que le moi ici? eh bien, c'est soi ClassAVC
qui a été délégué!
étape 6: Enfin, recherchez le pragma étape 6 dans ClassAVC
et utilisons les fonctions de la protocol
, commencez à taper func changeBackgroundColor et vous verrez qu'il le remplit automatiquement pour vous. Vous pouvez ajouter n'importe quelle implémentation à l'intérieur, dans cet exemple, nous allons simplement changer la couleur d'arrière-plan, 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 utilisez probablement sans même avis, si vous créez une tableview
délégation dans le passé, vous avez utilisé de nombreuses classes d' UIKIT
œuvres autour d'eux et bien d'autres frameworks
aussi, ils résolvent ces principaux problèmes.
Félicitations, vous venez d'implémenter un délégué personnalisé, je sais que vous pensez probablement, tant de mal juste pour ça? eh bien, la délégation est un modèle de conception très important pour comprendre si vous voulez devenir iOS
développeur, et gardez toujours à l'esprit qu'ils ont une relation un à un entre les objets.
Vous pouvez voir le tutoriel original ici
La réponse est en fait répondue, mais je voudrais vous donner une "feuille de triche" pour créer 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
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{
}
À mon avis, créez une classe distincte pour cette méthode déléguée et vous pouvez l'utiliser où vous le souhaitez.
dans mon DropDownClass.h personnalisé
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 ce fichier in.m créer 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 cela, vous pouvez utiliser cette méthode déléguée où vous le souhaitez.Par exemple ...
dans mon autre importation de viewcontroller après cela
créer une action pour appeler la méthode déléguée 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;
}
}
Délégué: - Créer
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
Envoyez et veuillez affecter un délégué pour voir que vous envoyez des données
[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. Implémentez la méthode dans la classe .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);
}
Commençons par un exemple, si nous achetons un produit en ligne, il passe par un processus tel que l'expédition / la livraison géré par différentes équipes. serait une surcharge pour d'autres personnes / le fournisseur pourrait vouloir transmettre ces informations 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 des vues multiples.
Voici le code considérer ShippingView comme équipe d'expédition et 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
//
}
}