¿Cómo puedo crear delegados en Objective-C?


Sé cómo trabajan los delegados, y sé cómo puedo usarlos.

Pero ¿cómo los creo?

Author: Wayne Chen, 2009-03-09

19 answers

Un delegado Objective-C es un objeto que ha sido asignado a la propiedad delegate otro objeto. Para crear una, simplemente defina una clase que implemente los métodos de delegado que le interesan y marque esa clase como implementando el protocolo de delegado.

Por ejemplo, supongamos que tiene un UIWebView. Si desea implementar sus delegados webViewDidStartLoad: método, usted podría crear una clase como esta:

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

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

Entonces podría crear una instancia de MyClass y asignar como delegado de la vista web:

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

En el lado UIWebView, probablemente tenga un código similar a este para ver si el delegado responde al mensaje webViewDidStartLoad: usando respondsToSelector: y envíalo si es apropiado.

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

La propiedad delegate en sí se suele declarar weak (en ARCO) o assign (pre-ARCO) para evitar los bucles de retención, ya que el delegado de un objeto a menudo tiene una fuerte referencia a ese objeto. (Por ejemplo, un controlador de vista es a menudo el delegado de una vista contener.)

Haciendo Delegados para Sus Clases

Para definir sus propios delegados, tendrá que declarar sus métodos en alguna parte, como se discute en los Documentos de Apple sobre protocolos. Normalmente declaras un protocolo formal. La declaración, parafraseada de UIWebView.h, se vería así:

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

Esto es análogo a una interfaz o clase base abstracta, ya que crea un tipo especial para su delegado, UIWebViewDelegate en este caso. Delegate implementors would have to adoptan el presente protocolo:

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

Y luego implementar los métodos en el protocolo. Para los métodos declarados en el protocolo como @optional (como la mayoría de los métodos delegados), debe verificar con -respondsToSelector: antes de llamar a un método en particular sobre él.

Nombrando

Los métodos delegados normalmente se nombran comenzando con el nombre de la clase delegante, y toman el objeto delegante como primer parámetro. También a menudo usan una forma de voluntad, debería o did. Entonces, webViewDidStartLoad: (el primer parámetro es la web view) en lugar de loadStarted (sin parámetros), por ejemplo.

Optimizaciones de velocidad

En lugar de comprobar si un delegado responde a un selector cada vez que queremos enviarlo un mensaje, puede almacenar en caché esa información cuando se establecen los delegados. Una forma muy limpia de hacer esto es usar un bitfield, de la siguiente manera:

@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

Luego, en el cuerpo, podemos verificar que nuestro delegado maneja los mensajes accediendo a nuestra estructura delegateRespondsTo, en lugar de enviar -respondsToSelector: una y otra vez nuevo.

Delegados informales

Antes de que existieran los protocolos, era común usar una categoría en NSObject para declarar los métodos que un delegado podía implementar. Por ejemplo, CALayer todavía hace esto:

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

Esto esencialmente le dice al compilador que cualquier objeto podría implementar displayLayer:.

Entonces usaría el mismo enfoque -respondsToSelector: como se describió anteriormente para llamar a este método. Los delegados simplemente implementan este método y asignan la propiedad delegate, y eso es todo (no hay declaración de que se ajusta a un protocolo). Este método es común en las bibliotecas de Apple, pero el nuevo código debería usar el enfoque de protocolo más moderno anterior, ya que este enfoque contamina NSObject (lo que hace que autocompletar sea menos útil) y hace que sea difícil para el compilador advertirte sobre errores tipográficos y errores similares.

 856
Author: Jesse Rusak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-25 20:02:47

La respuesta aprobada es genial, pero si estás buscando una respuesta de 1 minuto, prueba esto:

MyClass.el archivo h debería tener este aspecto (¡agregue líneas de delegado con comentarios!)

#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

MyClass.el archivo m debe tener este aspecto

#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

Para usar su delegado en otra clase (UIViewController llamado MyVC en este caso) 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

Implementar el método delegado

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}
 366
Author: Tibidabo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-11 13:40:41

Cuando se utiliza el método de protocolo formal para crear soporte de delegado, he encontrado que se puede garantizar una comprobación de tipo adecuada (aunque, tiempo de ejecución, no tiempo de compilación) agregando algo como:

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

En el código del accessor delegado (setDelegate). Esto ayuda a minimizar los errores.

 18
Author: umop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-04 20:42:59

Tal vez esto es más en la línea de lo que te estás perdiendo:

Si viene desde un punto de vista similar al de C++, los delegados tardan un poco en acostumbrarse, pero básicamente "solo funcionan".

La forma en que funciona es estableciendo algún objeto que escribió como delegado en NSWindow, pero su objeto solo tiene implementaciones (métodos) para uno o algunos de los muchos métodos delegados posibles. Así que algo sucede, y NSWindow quiere llamar a su objeto-solo utiliza Objective-c respondsToSelector método para determinar si su objeto quiere que se llame a ese método y, a continuación, lo llama. Así es como funciona objective-c-los métodos son buscados bajo demanda.

Es totalmente trivial hacer esto con tus propios objetos, no hay nada especial pasando, podrías por ejemplo tener un NSArray de 27 objetos, todos tipos diferentes de objetos, solo 18 algunos de ellos con el método -(void)setToBue; Los otros 9 no. Así que para llamar setToBlue a todos los 18 que lo necesitan, algo como esto:{[9]]}

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

El otro lo que pasa con los delegados es que no se conservan, por lo que siempre debe establecer el delegado en nil en su método MyClass dealloc.

 17
Author: Tom Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-20 17:42:20

Por favor! consulte el tutorial paso a paso para comprender cómo funcionan los delegados en iOS.

Delegar en iOS

He creado dos ViewController (para enviar datos de uno a otro)

  1. FirstViewController implementa el delegado (que proporciona datos).
  2. SecondViewController declara el delegado (que recibirá los datos).
 17
Author: swiftBoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-04 06:34:23

Como una buena práctica recomendada por Apple, es bueno para el delegado (que es un protocolo, por definición), ajustarse al protocolo NSObject.

@protocol MyDelegate <NSObject>
    ...
@end

& para crear métodos opcionales dentro de su delegado (es decir, métodos que no necesariamente deben implementarse), puede usar la anotación @optional como esta:

@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

Así que al usar métodos que ha especificado como opcionales, necesita (en su clase) verificar con respondsToSelector si la vista (que se ajusta a su delegado) realmente tiene aplicado su método opcional(s) o no.

 15
Author: Jean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-26 12:28:43

Creo que todas estas respuestas tienen mucho sentido una vez que entiendes a los delegados. Personalmente, vine de la tierra de C / C++ y antes de que los lenguajes de procedimiento como Fortran, etc, así que aquí está mi opinión de 2 minutos sobre la búsqueda de análogos similares en el paradigma de C++.

Si tuviera que explicar los delegados a un programador de C++/Java diría

¿Qué son los delegados ? Estos son punteros estáticos a clases dentro de otra clase. Una vez que asigne un puntero, puede llamar a funciones/métodos en esa clase. Por lo tanto, algunas funciones de su clase son "delegadas" (En C++ world - puntero a por un puntero de objeto de clase) a otra clase.

¿Qué son los protocolos ? Conceptualmente sirve como un propósito similar al archivo de encabezado de la clase que está asignando como una clase delegada. Un protocolo es una forma explícita de definir qué métodos deben implementarse en la clase cuyo puntero se estableció como delegado dentro de una clase.

¿Cómo puedo hacer algo similar en C++? Si intentaste hacer esto en C++, lo haría definiendo punteros a clases (objetos) en la definición de clase y luego conectándolos a otras clases que proporcionarán funciones adicionales como delegados a su clase base. Pero este cableado necesita ser maitained dentro del código y será torpe y propenso a errores. Objective C solo asume que los programadores no son los mejores para mantener esta decipline y proporciona restricciones de compilador para hacer cumplir una implementación limpia.

 10
Author: DrBug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-19 10:34:42

Versión Swift

Un delegado es solo una clase que hace algún trabajo para otra clase. Lea el siguiente código para ver un ejemplo un tanto tonto (pero esperemos que esclarecedor) de Playground que muestra cómo se hace esto en 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 la práctica, los delegados se utilizan a menudo en las siguientes situaciones

  1. Cuando una clase necesita comunicar alguna información a otra clase
  2. Cuando una clase quiere permitir que otra clase la personalice

El las clases no necesitan saber nada entre sí de antemano, excepto que la clase delegate cumple con el protocolo requerido.

Recomiendo encarecidamente leer los siguientes dos artículos. Me ayudaron a entender a los delegados incluso mejor que la documentación .

 9
Author: Suragch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-02 14:45:08

Ok, esto no es realmente una respuesta a la pregunta, pero si usted está buscando cómo hacer su propio delegado tal vez algo mucho más simple podría ser una mejor respuesta para usted.

Apenas implemento a mis delegados porque rara vez lo necesito. Solo puedo tener UN delegado para un objeto delegado. Por lo tanto, si desea que su delegado para la comunicación/transferencia de datos de una sola vía, es mucho mejor con las notificaciones.

NSNotification puede pasar objetos a más de un destinatario y es muy fácil de usar. Funciona así:

MyClass.el archivo m debe tener este aspecto

#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

Para usar su notificación en otras clases: Añadir clase como observador:

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

Implementa el selector:

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

No olvides eliminar tu clase como observador si

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
 8
Author: Tibidabo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-16 23:23:13

Digamos que tienes una clase que desarrollaste y quieres declarar una propiedad delegate para poder notificarla cuando ocurre algún 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

Por lo que declara un protocolo en el archivo de encabezado MyClass (o un archivo de encabezado separado), y declara los controladores de eventos requeridos/opcionales que su delegado debe/debe implementar, luego declara una propiedad en MyClass de tipo (id< MyClassDelegate>), lo que significa que cualquier clase de objective c que se ajuste al protocolo MyClassDelegate, notará que la propiedad declarado como débil, esto es muy importante para evitar el ciclo retain (la mayoría de las veces el delegado retiene la instancia MyClass, por lo que si declaras al delegado como retain, ambos se retendrán entre sí y ninguno de ellos será liberado).

También notará que los métodos de protocolo pasan la instancia MyClass al delegado como parámetro , esta es la mejor práctica en caso de que el delegado quiera llamar a algunos métodos en la instancia MyClass y también ayuda cuando el delegado se declara como MyClassDelegate a múltiples instancias MyClass, como cuando tienes múltiples instancias UITableView's en tu ViewController y se declara como UITableViewDelegate a todas ellas.

Y dentro de su MyClass notifica al delegado con eventos declarados de la siguiente manera:

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

Primero verifique si su delegado responde al método de protocolo que está a punto de llamar en caso de que el delegado no lo implemente y la aplicación se bloquee (incluso si se requiere el método de protocolo).

 8
Author: m.eldehairy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-06 10:23:13

Aquí hay un método simple para crear delegados

Crear protocolo en .archivo h. Asegúrese de que está definido antes del protocolo usando @class seguido del nombre del controlador UIViewController < As the protocol I am going to use is UIViewController class>.

Paso: 1: Cree un nuevo Protocolo de clase llamado "YourViewController" que será la subclase de la clase UIViewController y asigne esta clase al segundo ViewController.

Paso: 2: Vaya al archivo "YourViewController" y modifíquelo como abajo:

#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

Los métodos definidos en el comportamiento del protocolo se pueden controlar con @optional y @required como parte de la definición del protocolo.

Paso: 3: Implementación de Delegate

    #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

/ / prueba si el método ha sido definido antes de llamarlo

 - (void) someMethodToCallDelegate {
     if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
           [self.delegate delegateMethodName:self]; 
     }
  }
 6
Author: Sujania,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-25 12:57:40

Para crear su propio delegado, primero debe crear un protocolo y declarar los métodos necesarios, sin implementar. Y luego implemente este protocolo en su clase de encabezado donde desea implementar los métodos delegate o delegate.

Un protocolo debe declararse de la siguiente manera:

@protocol ServiceResponceDelegate <NSObject>

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

@end

Esta es la clase de servicio donde se debe realizar alguna tarea. Muestra cómo definir delegado y cómo configurar el delegado. En la clase de implementación después de que se complete la tarea, delegate se llama a los métodos.

@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

Esta es la clase de vista principal desde donde se llama a la clase de servicio configurando el delegado a sí mismo. Y también el protocolo se implementa en la clase 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];
}

Eso es todo, y al implementar métodos de delegado en esta clase, control regresará una vez que la operación/tarea esté terminada.

 5
Author: Mahesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-02 17:12:52

Descargo de responsabilidad: esta es la versión Swift de cómo crear un delegate.

Entonces, ¿qué son los delegados? ...en el desarrollo de software, hay arquitecturas de soluciones reutilizables generales que ayudan a resolver problemas que ocurren comúnmente dentro de un contexto dado, estas "plantillas", por así decirlo, son mejor conocidas como patrones de diseño. Los delegados son un patrón de diseño que permite que un objeto envíe mensajes a otro objeto cuando ocurre un evento específico. Imagine un objeto A llama a un objeto B para realizar un acto. Una vez que la acción está completa, el objeto A debe saber que B ha completado la tarea y tomar las medidas necesarias, esto se puede lograr con la ayuda de los delegados!

Para una mejor explicación, voy a mostrarle cómo crear un delegado personalizado que pase datos entre clases, con Swift en una aplicación simple, ¡comience descargando o clonando este proyecto de inicio y ejecútelo!

Puedes ver una aplicación con dos clases, ViewController A y ViewController B. B tiene dos vistas que en grifo cambia el color de fondo del ViewController, nada demasiado complicado ¿verdad? bueno, ahora vamos a pensar de una manera fácil para cambiar también el color de fondo de la clase A cuando las vistas de la clase B son pulsadas.

El problema es que estos puntos de vista son parte de la clase B y no tienen idea de la clase A, por lo que necesitamos encontrar una manera de comunicarse entre estas dos clases, y ahí es donde brilla la delegación. Dividí la implementación en 6 pasos para que pueda usar esto como una hoja de trucos cuando lo necesite se.

Paso 1: Busque la marca pragma paso 1 en el archivo ClassBVC y agregue esto

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

El primer paso es crear un protocol, en este caso, crearemos el protocolo en clase B, dentro del protocolo puede crear tantas funciones como desee en función de los requisitos de su implementación. En este caso, solo tenemos una función simple que acepta un UIColor opcional como argumento. Es una buena práctica nombrar sus protocolos agregando la palabra delegate al final de la clase nombre, en este caso, ClassBVCDelegate.

Paso 2: Busque la marca pragma paso 2 en ClassVBC y agregue esto

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

Aquí simplemente creamos una propiedad delegate para la clase, esta propiedad debe adoptar el tipo protocol, y debe ser opcional. Además, debe agregar la palabra clave débil antes de la propiedad para evitar ciclos de retención y posibles fugas de memoria, si no sabe lo que eso significa, no se preocupe por ahora, solo recuerde agregar esta palabra clave.

Paso 3: Busque el paso de la marca pragma 3 dentro del handleTap method en ClassBVC y añadir esto

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

Una cosa que debe saber, ejecute la aplicación y toque en cualquier vista, no verá ningún comportamiento nuevo y eso es correcto, pero lo que quiero señalar es que la aplicación no se bloquea cuando se llama al delegado, y es porque lo creamos como un valor opcional y es por eso que no se bloquea incluso el delegado no existe todavía. Vamos ahora a ClassAVC archivo y hacerlo, el delegado.

Paso 4: Busque el pragma marque el paso 4 dentro del método handleTap en ClassAVC y agregue esto al lado de su tipo de clase de esta manera.

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

Ahora ClassAVC adoptó el protocolo ClassBVCDelegate, puede ver que su compilador le está dando un error que dice " Type 'ClassAVC no se ajusta al protocolo 'ClassBVCDelegate' y esto solo significa que aún no utilizó los métodos del protocolo, imagine que cuando la clase A adopta el protocolo es como firmar un contrato con la clase B y este contrato dice " Cualquier clase que adopta me DEBE usar mis funciones!"

Nota rápida: Si vienes de un fondo Objective-C probablemente estés pensando que también puedes callar ese error haciendo que ese método sea opcional, pero para mi sorpresa, y probablemente la tuya, Swift el lenguaje no soporta opcional protocols, si quieres hacerlo puedes crear una extensión para tu protocol o usar la palabra clave @objc en tu implementación protocol.

Personalmente, Si tengo que crear un protocolo con diferentes métodos opcionales prefiero para dividirlo en diferentes protocols, de esa manera seguiré el concepto de dar una sola responsabilidad a mis objetos, pero puede variar en función de la implementación específica.

Aquí está un buen artículo sobre métodos opcionales.

Paso 5: Busque la marca pragma paso 5 dentro del método prepare for segue y agregue esto

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

Aquí solo estamos creando una instancia de ClassBVC y asignamos su delegado a self, pero ¿qué es self aquí? bueno, el yo es el ClassAVC ¡que ha sido delegada!

Paso 6: Finalmente, busque el pragma paso 6 en ClassAVC y usemos las funciones de protocol, comience a escribir func changeBackgroundColor y verá que lo está completando automáticamente por usted. Puede agregar cualquier implementación dentro de él, en este ejemplo, solo cambiaremos el color de fondo, agregue esto.

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

Ahora ejecute la aplicación!

Delegates están en todas partes y probablemente los use sin previo aviso, si crea un tableview en en el pasado se utilizó la delegación, muchas clases de UIKIT trabaja alrededor de ellos y muchos otros frameworks también, resuelven estos problemas principales.

  • Evite el acoplamiento apretado de objetos.
  • Modifica el comportamiento y la apariencia sin necesidad de subclasificar objetos.
  • Permite que las tareas sean manejadas a cualquier objeto arbitrario.

Felicitaciones, usted acaba de implementar un delegado personalizado, sé que usted está pensando probablemente, tanto problema solo por esto? bueno, la delegación es un patrón de diseño muy importante para entender si desea convertirse en un desarrollador iOS, y siempre tenga en cuenta que tienen una relación uno a uno entre los objetos.

Puedes ver el tutorial original aquí

 3
Author: James Rochabrun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-23 11:00:22

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étodo:

-(void)delegateMEthod: (ArgType) arg{
}
 2
Author: Lal Krishna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-19 04:14:58

En mi punto de vista, cree una clase separada para ese método delegado y puede usarla donde quiera.

En mi DropDownClass Personalizado.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;

Después de eso en.m archivo crear matriz con objetos,

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

Aquí todos están configurados para la clase delegada personalizada.después de eso, puede usar este método de delegado donde desee.por ejemplo...

En mi otra importación de viewcontroller después de eso

Crear acción para llamar al método delegado de esta manera

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

Después de eso llamar al método delegado como este

- (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
Author: Mangi Reddy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-08 09:30:59

Delegar: - Crear

@protocol addToCartDelegate <NSObject>

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

@end

Enviar y por favor asignar delegado para ver que está enviando datos

[self.delegate addToCartAction:itemsModel isAdded:YES];
 0
Author: Vaibhav Gaikwad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-08 10:50:58
//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. Implementar el método en la clase .m - (void)didRemoveCellWithTag: (NSInteger)tag { NSLog@("Tag % d", tag);

}

 0
Author: Rohit Kashyap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-02 16:31:44

Comencemos con un ejemplo, si compramos un producto en línea, pasa por un proceso como el envío/entrega manejado por diferentes teams.So si el envío se completa, el equipo de envío debe notificar al equipo de entrega y debe ser una comunicación individual, ya que transmitir esta información sería una sobrecarga para otras personas / el proveedor podría querer pasar esta información solo a las personas requeridas.

Así que si pensamos en términos de nuestra aplicación, un evento puede ser un pedido en línea y diferentes equipos pueden ser como múltiples vistas.

Aquí está el código considere ShippingView como equipo de envío y DeliveryView como equipo de entrega:

//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
Author: Ellen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-14 10:14:49

La respuesta es realmente respondida, pero me gustaría darle una "hoja de trucos" para crear un delegado:

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
 0
Author: Miras Maratuly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-16 04:40:48