Domanda

So come funzionano i delegati e so come posso usarli.

Ma come li creo?

È stato utile?

Soluzione

Un delegato Objective-C è un oggetto che è stato assegnato alla proprietà delegate un altro oggetto. Per crearne uno, devi semplicemente definire una classe che implementa i metodi delegati che ti interessano e contrassegnare quella classe come implementazione del protocollo delegato.

Ad esempio, supponiamo di avere un UIWebView. Se desideri implementare webViewDidStartLoad: , puoi creare una classe come questa:

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

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

Quindi è possibile creare un'istanza di MyClass e assegnarla come delegato della vista Web:

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

Sul lato respondsToSelector:, probabilmente ha un codice simile a questo per vedere se il delegato risponde al messaggio weak usando assign e inviarlo se appropriato.

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

La proprietà del delegato stessa viene in genere dichiarata UIWebViewDelegate (in ARC) o @optional (pre-ARC) per evitare cicli di mantenimento, poiché il delegato di un oggetto contiene spesso un forte riferimento a quell'oggetto. (Ad esempio, un controller di vista è spesso delegato di una vista in esso contenuta.)

Creazione di delegati per le tue lezioni

Per definire i tuoi delegati, dovrai dichiarare i loro metodi da qualche parte, come discusso nella Documenti Apple sui protocolli . Di solito dichiari un protocollo formale. La dichiarazione, parafrasata da UIWebView.h, sarebbe simile a questa:

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

Ciò è analogo a un'interfaccia o a una classe di base astratta, in quanto crea un tipo speciale per il delegato, -respondsToSelector: in questo caso. Gli implementatori delegati dovrebbero adottare questo protocollo:

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

E quindi implementare i metodi nel protocollo. Per i metodi dichiarati nel protocollo come loadStarted (come la maggior parte dei metodi delegati), è necessario verificare con delegateRespondsTo prima di chiamare un particolare metodo su di esso.

Naming

I metodi delegati sono in genere denominati a partire dal nome della classe delegante e prendono l'oggetto delegante come primo parametro. Spesso usano anche una volontà, una forma o una forma. Pertanto, ad esempio NSObject (il primo parametro è la vista Web) anziché CALayer (non accetta parametri).

Ottimizzazioni della velocità

Invece di verificare se un delegato risponde a un selettore ogni volta che vogliamo inviargli un messaggio, puoi memorizzare tali informazioni quando i delegati sono impostati. Un modo molto pulito per farlo è usare un bitfield, come segue:

@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

Quindi, nel corpo, possiamo verificare che il nostro delegato gestisca i messaggi accedendo alla nostra displayLayer: struttura, piuttosto che inviando <=> più e più volte.

Delegati informali

Prima dell'esistenza dei protocolli, era comune utilizzare un categoria su <=> per dichiarare i metodi che un delegato potrebbe implementare. Ad esempio, <=> continua a farlo:

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

Questo essenzialmente dice al compilatore che qualsiasi oggetto potrebbe implementare <=>.

Dovresti quindi utilizzare lo stesso approccio <=> come descritto sopra per chiamare questo metodo. I delegati implementano semplicemente questo metodo e assegnano la proprietà <=> e il gioco è fatto (non è possibile dichiarare la conformità a un protocollo). Questo metodo è comune nelle librerie di Apple, ma il nuovo codice dovrebbe utilizzare l'approccio di protocollo più moderno sopra, poiché questo approccio inquina <=> (il che rende meno utile il completamento automatico) e rende difficile per il compilatore avvisarti di errori di battitura e errori simili.

Altri suggerimenti

La risposta approvata è ottima, ma se stai cercando una risposta da 1 minuto prova questo:

Il file MyClass.h dovrebbe assomigliare a questo (aggiungere linee delegate con commenti!)

#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

Il file MyClass.m dovrebbe apparire così

#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

Per utilizzare il delegato in un'altra classe (in questo caso UIViewController chiamato MyVC) MyVC.h:

#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}

MyVC.m:

myClass.delegate = self;          //set its delegate to self somewhere

Implementa metodo delegato

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

Quando si utilizza il metodo del protocollo formale per la creazione del supporto delegato, ho scoperto che è possibile garantire un controllo del tipo corretto (sebbene, tempo di esecuzione, non tempo di compilazione) aggiungendo qualcosa di simile:

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

nel tuo codice di accesso delegato (setDelegate). Questo aiuta a minimizzare gli errori.

Forse questo è più sulla falsariga di ciò che ti manca:

Se provieni da un punto di vista simile al C ++, i delegati impiegano un po 'ad abituarsi, ma fondamentalmente "funzionano e basta".

Il modo in cui funziona è impostare un oggetto che hai scritto come delegato su NSWindow, ma il tuo oggetto ha implementazioni (metodi) solo per uno o alcuni dei molti possibili metodi delegati. Quindi succede qualcosa e NSWindow vuole chiamare il tuo oggetto - usa solo il metodo respondsToSelector di Objective-c per determinare se il tuo oggetto vuole quel metodo chiamato, e poi lo chiama. Ecco come funziona Object-C: i metodi vengono cercati su richiesta.

È assolutamente banale farlo con i tuoi oggetti, non c'è niente di speciale in corso, potresti ad esempio avere un NSArray di 27 oggetti, tutti i diversi tipi di oggetti, solo 18 hanno il metodo - (void) setToBue; Gli altri 9 no. Quindi, per chiamare setToBlue su tutti i 18 che ne hanno bisogno, qualcosa del genere:

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

L'altra cosa che riguarda i delegati è che non vengono mantenuti, quindi devi sempre impostare il delegato su nil nel tuo metodo MyClass dealloc .

! controlla di seguito un semplice tutorial passo passo per capire come funzionano i delegati in iOS.

  

Delega in iOS

Ho creato due ViewController (per l'invio di dati l'uno dall'altro)

  1. FirstViewController implementare delegate (che fornisce dati).
  2. SecondViewController dichiara il delegato (che riceverà i dati).

Come buona pratica raccomandata da Apple, è bene che il delegato (che è un protocollo, per definizione), sia conforme al protocollo NSObject .

@protocol MyDelegate <NSObject>
    ...
@end

& amp; per creare metodi opzionali all'interno del tuo delegato (ovvero metodi che non devono necessariamente essere implementati), puoi utilizzare l'annotazione @optional in questo modo:

@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

Pertanto, quando si utilizzano i metodi specificati come facoltativi, è necessario (nella propria classe) verificare con respondsToSelector se la vista (conforme al proprio delegato) ha effettivamente implementato il metodo opzionale ( s) oppure no.

Penso che tutte queste risposte abbiano molto senso dopo aver capito i delegati. Personalmente vengo dalla terra di C / C ++ e prima di quei linguaggi procedurali come Fortran ecc. Quindi ecco la mia opinione di 2 minuti per trovare analoghi simili nel paradigma C ++.

Se dovessi spiegare i delegati a un programmatore C ++ / Java, direi

Cosa sono i delegati? Questi sono puntatori statici alle classi all'interno di un'altra classe. Dopo aver assegnato un puntatore, è possibile chiamare funzioni / metodi in quella classe. Quindi alcune funzioni della tua classe sono "delegate" (Nel mondo C ++ - puntatore a da un puntatore oggetto classe) a un'altra classe.

Cosa sono i protocolli? Concettualmente serve come scopo simile al file di intestazione della classe che si sta assegnando come classe delegata. Un protocollo è un modo esplicito per definire quali metodi devono essere implementati nella classe il cui puntatore è stato impostato come delegato all'interno di una classe.

Come posso fare qualcosa di simile in C ++? Se hai provato a farlo in C ++, definiresti i puntatori alle classi (oggetti) nella definizione della classe e poi collegandoli ad altre classi che forniranno funzioni aggiuntive come delegati alla tua classe base. Ma questo cablaggio deve essere mantenuto nel codice e sarà goffo e soggetto a errori. L'obiettivo C presuppone solo che i programmatori non siano i migliori a mantenere questa deciplina e fornisce restrizioni al compilatore per imporre un'implementazione pulita.

Versione Swift

Un delegato è solo una classe che fa del lavoro per un'altra classe. Leggi il seguente codice per un esempio di Playground un po 'sciocco (ma si spera illuminante) che mostra come questo viene fatto in 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!"
}

Nella pratica reale, i delegati vengono spesso utilizzati nelle seguenti situazioni

  1. Quando una classe deve comunicare alcune informazioni a un'altra classe
  2. Quando una classe vuole consentire ad un'altra classe di personalizzarla

Le classi non devono prima conoscersi reciprocamente, tranne per il fatto che la classe delegata è conforme al protocollo richiesto.

Consiglio vivamente di leggere i seguenti due articoli. Mi hanno aiutato a capire i delegati anche meglio della documentazione fatto.

Ok, questa non è davvero una risposta alla domanda, ma se stai cercando come rendere il tuo delegato forse qualcosa di molto più semplice potrebbe essere una risposta migliore per te.

Difficilmente implemento i miei delegati perché raramente ne ho bisogno. Posso avere UN SOLO delegato per un oggetto delegato. Quindi, se si desidera che il proprio delegato comunichi / passi i dati in un modo di quanto sia meglio con le notifiche.

NSNotification può passare oggetti a più destinatari ed è molto facile da usare. Funziona così:

Il file MyClass.m dovrebbe apparire così

#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

Per utilizzare la notifica in altre classi: Aggiungi classe come osservatore:

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

Implementa il selettore:

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

Non dimenticare di rimuovere la tua classe come osservatore se

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

supponiamo che tu abbia una classe che hai sviluppato e desideri dichiarare una proprietà delegata per poterla notificare quando si verifica un evento:

@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

in modo da dichiarare un protocollo nel file di intestazione MyClass (o un file di intestazione separato) e dichiarare i gestori di eventi obbligatori / facoltativi che il delegato deve / dovrebbe implementare, quindi dichiarare una proprietà in MyClass di tipo ( id < MyClassDelegate > ) che indica qualsiasi classe c obiettiva conforme al protocollo MyClassDelegate , noterai che la proprietà delegate è dichiarato debole, questo è molto importante per prevenire il ciclo di conservazione (il più delle volte il delegato conserva l'istanza MyClass , quindi se hai dichiarato il delegato come mantenimento, entrambi si manterranno a vicenda e nessuno dei due mai essere rilasciato).

noterai anche che i metodi del protocollo passano l'istanza MyClass al delegato come parametro, questa è la migliore pratica nel caso in cui il delegato desideri chiamare alcuni metodi su MyClass istanza e aiuta anche quando il delegato si dichiara come MyClassDelegate in più istanze MyClass , come quando hai più istanze UITableView nel tuo ViewController e si dichiara come UITableViewDelegate per tutti loro.

e all'interno del tuo MyClass comunichi al delegato gli eventi dichiarati come segue:

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

per prima cosa controlla se il tuo delegato risponde al metodo del protocollo che stai per chiamare nel caso in cui il delegato non lo implementi e quindi l'app andrà in crash (anche se è richiesto il metodo del protocollo).

Ecco un metodo semplice per creare delegati

Crea protocollo nel file .h. Assicurati che sia definito prima del protocollo usando @class seguito dal nome di UIViewController < Come protocollo che userò è la classe UIViewController > ;.

Passaggio: 1: crea un nuovo protocollo di classe denominato " YourViewController " che sarà la sottoclasse della classe UIViewController e assegnerà questa classe al secondo ViewController.

Passaggio: 2: vai a " YourViewController " file e modificarlo come di seguito:

#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

I metodi definiti nel comportamento del protocollo possono essere controllati con @optional e @required come parte della definizione del protocollo.

Passaggio: 3: Implementazione del delegato

    #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

// verifica se il metodo è stato definito prima di chiamarlo

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

Per creare il tuo delegato, devi prima creare un protocollo e dichiarare i metodi necessari, senza implementarlo. E quindi implementare questo protocollo nella classe di intestazione in cui si desidera implementare i metodi delegate o delegate.

Un protocollo deve essere dichiarato come di seguito:

@protocol ServiceResponceDelegate <NSObject>

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

@end

Questa è la classe di servizio in cui è necessario eseguire alcune attività. Mostra come definire il delegato e come impostare il delegato. Nella classe di implementazione dopo che l'attività è stata completata, vengono chiamati i metodi del delegato.

@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

Questa è la classe della vista principale da cui viene chiamata la classe di servizio impostando il delegato su se stesso. E anche il protocollo è implementato nella classe header.

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

- (void) go;

@end

@implementation viewController

//
//some methods
//

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

Ecco fatto, e implementando metodi delegati in questa classe, il controllo tornerà al termine dell'operazione / attività.

Disclaimer: questa è la versione Swift su come creare un delegato .

Quindi, cosa sono i delegati? & # 8230; nello sviluppo del software, ci sono architetture di soluzioni riutilizzabili generali che aiutano a risolvere i problemi più comuni in un determinato contesto, questi modelli & # 8221 ;, per così dire, sono meglio conosciuti come modelli di progettazione. I delegati sono un modello di progettazione che consente a un oggetto di inviare messaggi a un altro oggetto quando si verifica un evento specifico. Immagina un oggetto A chiama un oggetto B per eseguire un'azione. Una volta completata l'azione, l'oggetto A dovrebbe sapere che B ha completato l'attività e intraprendere le azioni necessarie, questo può essere realizzato con l'aiuto dei delegati!

Per una spiegazione migliore, ti mostrerò come creare un delegato personalizzato che passa i dati tra le classi, con Swift in una semplice applicazione, inizia scaricando o clonando questo progetto iniziale ed eseguilo!

Puoi vedere un'app con due classi, ViewController A e ViewController B . B ha due viste che al tocco cambiano il colore di sfondo del ViewController , niente di troppo complicato, giusto? bene ora pensiamo in un modo semplice di cambiare anche il colore di sfondo della classe A quando vengono toccate le viste sulla classe B.

Il problema è che queste viste fanno parte della classe B e non hanno idea della classe A, quindi dobbiamo trovare un modo per comunicare tra queste due classi e quella in cui brilla la delega. Ho suddiviso l'implementazione in 6 passaggi in modo da poterlo utilizzare come cheat sheet quando ne hai bisogno.

passaggio 1: cercare il segno pragma passaggio 1 nel file ClassBVC e aggiungere questo

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

Il primo passo è creare un protocollo , in questo caso creeremo il protocollo in classe B, all'interno del protocollo puoi creare tutte le funzioni che desideri in base ai requisiti del tuo implementazione. In questo caso, abbiamo solo una semplice funzione che accetta un UIColor come argomento. È buona norma nominare i protocolli aggiungendo la parola delegate alla fine del nome della classe, in questo caso ClassBVCDelegate .

passaggio 2: cercare il segno pragma passaggio 2 in ClassVBC e aggiungere questo

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

Qui creiamo solo una proprietà delegata per la classe, questa proprietà deve adottare il tipo protocol e dovrebbe essere facoltativa. Inoltre, dovresti aggiungere la parola chiave debole prima della proprietà per evitare cicli di mantenimento e potenziali perdite di memoria, se non sai cosa significa che non ti preoccupi per ora, ricorda di aggiungere questa parola chiave.

passaggio 3: cercare il segno pragma passaggio 3 all'interno del metodo handleTap in ClassBVC e aggiungere questo

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

Una cosa che dovresti sapere, esegui l'app e tocca qualsiasi vista, non vedrai alcun nuovo comportamento e questo è corretto ma la cosa che voglio sottolineare è che l'app è & Non si arresta in modo anomalo quando viene chiamato il delegato, ed è perché lo creiamo come valore facoltativo e questo è il motivo per cui non si blocca anche il delegato non esiste ancora . Ora andiamo al file ClassAVC e rendiamolo delegato.

passaggio 4: cercare il segno pragma passaggio 4 all'interno del metodo handleTap in ClassAVC e aggiungere questo accanto al tipo di classe in questo modo.

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

Ora ClassAVC ha adottato il protocollo ClassBVCDelegate , puoi vedere che il tuo compilatore ti sta dando un errore che dice & # 8220; Digita & # 8216; ClassAVC non è conforme al protocollo & # 8216; ClassBVCDelegate & # 8217; e questo significa solo che non hai ancora usato i metodi del protocollo, immagina che quando la classe A adotta il protocollo è come firmare un contratto con la classe B e questo contratto dice & # 8220; Qualsiasi classe che mi adotta DEVE usare il mio funzioni di & # 8221;

Nota rapida: se provieni da uno sfondo Objective-C probabilmente stai pensando che puoi anche chiudere quell'errore rendendo quel metodo opzionale, ma per mia sorpresa, e probabilmente tuo, Swift non supporta i protocolli opzionali, se vuoi farlo puoi creare un'estensione per il tuo protocollo o usare la parola chiave @objc nel tuo < implementazione di code> protocol .

Personalmente, se dovessi creare un protocollo con diversi metodi opzionali, preferirei suddividerlo in diversi protocolli , in questo modo seguirò il concetto di dare un'unica responsabilità ai miei oggetti, ma può variare in base all'implementazione specifica.

ecco un buon articolo sui metodi opzionali .

passaggio 5: cercare il segno pragma passaggio 5 all'interno del metodo di preparazione per segue e aggiungere questo

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

Qui stiamo solo creando un'istanza di ClassBVC e assegniamo il suo delegato a sé, ma che cosa è sé qui? bene, self è il ClassAVC che è stato delegato!

passaggio 6: Infine, cerca il pragma passaggio 6 in ClassAVC e usa le funzioni del protocollo , inizia a digitare func changeBackgroundColor e vedrai che lo sta completando automaticamente per te. Puoi aggiungere qualsiasi implementazione al suo interno, in questo esempio, cambieremo semplicemente il colore di sfondo, aggiungendolo.

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

Ora esegui l'app!

Delegati sono ovunque e probabilmente li usi senza nemmeno preavviso, se in passato hai creato una tableview in passato hai usato la delega, molte classi di UIKIT funziona attorno a loro e anche a molti altri framework , risolvono questi problemi principali.

  • Evitare l'accoppiamento stretto di oggetti.
  • Modifica il comportamento e l'aspetto senza la sottoclasse degli oggetti.
  • Consenti alle attività di essere gestite su qualsiasi oggetto arbitrario.

Congratulazioni, hai appena implementato un delegato personalizzato, so che probabilmente stai pensando, così tanti problemi solo per questo? bene, la delega è un modello di progettazione molto importante per capire se vuoi diventare uno sviluppatore iOS e tieni sempre presente che hanno una relazione uno a uno tra gli oggetti.

Puoi vedere il tutorial originale qui

La risposta è in realtà una risposta, ma vorrei darti un "cheat sheet" per la creazione di un delegato:

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;

Metodo:

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

Dal mio punto di vista, crea una classe separata per quel metodo delegato e puoi usare dove vuoi.

nel mio DropDownClass.h personalizzato

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;

dopo quel file in.m crea un array con oggetti,

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

Qui tutti sono impostati per la classe delegata personalizzata. Successivamente puoi usare questo metodo delegato dove vuoi.per esempio ...

nella mia altra importazione viewcontroller dopo che

crea un'azione per chiamare il metodo delegato come questo

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

dopo quella chiamata del metodo delegato come questo

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

Delegato: - Crea

@protocol addToCartDelegate <NSObject>

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

@end

Invia e assegna un delegato per visualizzare l'invio di dati

[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. Implementare il metodo nella classe .m - (void) didRemoveCellWithTag: tag (NSInteger) {    NSLog @ (" Tag% d ", tag);

}

Cominciamo con un esempio, se acquistiamo un prodotto online, passa attraverso un processo come la spedizione / consegna gestita da diversi team, quindi se la spedizione viene completata, il team di spedizione dovrebbe avvisare il team di consegna & amp; dovrebbe essere una comunicazione uno a uno in quanto la trasmissione di queste informazioni sarebbe sovraccarica per le altre persone / il fornitore potrebbe voler passare queste informazioni solo alle persone richieste.

Quindi, se pensiamo in termini della nostra app, un evento può essere un ordine online & amp; team diversi possono essere come visualizzazioni multiple.

Ecco il codice considera ShippingView come team di spedizione & amp; DeliveryView come team di consegna:

//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
        //
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top