Sé cómo funcionan los delegados y sé cómo puedo usarlos.
¿Pero cómo los creo?
Sé cómo funcionan los delegados y sé cómo puedo usarlos.
¿Pero cómo los creo?
Respuestas:
Un delegado de Objective-C es un objeto que ha sido asignado a la delegate
propiedad de otro objeto. Para crear uno, usted define una clase que implementa los métodos de delegado que le interesan, y marca esa clase como la implementación del protocolo de delegado.
Por ejemplo, suponga que tiene un UIWebView
. Si desea implementar el webViewDidStartLoad:
método de su delegado , puede crear una clase como esta:
@interface MyClass<UIWebViewDelegate>
// ...
@end
@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
@end
Luego, podría crear una instancia de MyClass y asignarla como delegado de la vista web:
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
Por UIWebView
otro lado, probablemente tenga un código similar a este para ver si el delegado responde al webViewDidStartLoad:
mensaje utilizando respondsToSelector:
y lo envía si corresponde.
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
La propiedad del delegado en sí se suele declarar weak
(en ARC) o assign
(pre-ARC) para evitar retener bucles, ya que el delegado de un objeto a menudo tiene una fuerte referencia a ese objeto. (Por ejemplo, un controlador de vista a menudo es el delegado de una vista que contiene).
Para definir sus propios delegados, tendrá que declarar sus métodos en algún lugar, como se discutió en los Documentos de Apple sobre protocolos . Usualmente 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. Los implementadores delegados tendrían que adoptar este 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 consultar -respondsToSelector:
antes de llamar a un método en particular.
Los métodos delegados generalmente se nombran comenzando con el nombre de la clase delegante y toman el objeto delegado 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 vista web) en lugar de loadStarted
(sin tomar parámetros), por ejemplo.
En lugar de verificar si un delegado responde a un selector cada vez que queremos enviarle un mensaje, puede almacenar en caché esa información cuando se configuran los delegados. Una forma muy limpia de hacer esto es usar un campo de bits, 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 delegateRespondsTo
estructura, en lugar de enviarlos -respondsToSelector:
una y otra vez.
Antes de que existieran los protocolos, era común el uso de una categoría en la NSObject
que declare los métodos delegado podría implementar. Por ejemplo, CALayer
todavía hace esto:
@interface NSObject(CALayerDelegate)
- (void)displayLayer:(CALayer *)layer;
// ... other methods here
@end
Esto le dice al compilador que cualquier objeto podría implementarse displayLayer:
.
A continuación, utilizaría el mismo -respondsToSelector:
enfoque que el descrito anteriormente para llamar a este método. Los delegados implementan este método y asignan la delegate
propiedad, y eso es todo (no hay declaración de que cumpla con 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 el autocompletado sea menos útil) y dificulta que el compilador le advierta sobre errores tipográficos y errores similares.
unsigned int
tipo a BOOL
como el valor de retorno de delegate respondsToSelector
es de tipo BOOL
.
La respuesta aprobada es excelente, pero si está buscando una respuesta de 1 minuto intente esto:
El archivo MyClass.h debería verse así (¡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
El archivo MyClass.m debería verse así
#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 método delegado
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(@"Delegates are great!");
}
myClass
instancia dentro de MyVC.m?
Al usar el método de protocolo formal para crear soporte de delegado, descubrí que puede garantizar una verificació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 su código de acceso delegado (setDelegate). Esto ayuda a minimizar los errores.
¡Por favor! revise a continuación el sencillo tutorial paso a paso para comprender cómo funciona Delegados en iOS.
He creado dos ViewControllers (para enviar datos de uno a otro)
Tal vez esto sea más parecido a lo que te estás perdiendo:
Si viene desde un punto de vista similar a C ++, los delegados tardan un poco en acostumbrarse, pero básicamente 'simplemente funcionan'.
La forma en que funciona es que establezca algún objeto que escribió como delegado a NSWindow, pero su objeto solo tiene implementaciones (métodos) para uno o algunos de los muchos posibles métodos de delegado. Entonces, sucede algo y NSWindow
quiere llamar a su objeto: solo usa el respondsToSelector
método Objective-c para determinar si su objeto quiere que se llame a ese método y luego lo llama. Así es como funciona Objective-C: los métodos se buscan a pedido.
Es totalmente trivial hacer esto con sus propios objetos, no está sucediendo nada especial, por ejemplo, puede tener uno NSArray
de 27 objetos, todos los diferentes tipos de objetos, solo 18 algunos de ellos tienen el método -(void)setToBue;
Los otros 9 no. Entonces, para llamar setToBlue
a los 18 que lo necesitan, algo como esto:
for (id anObject in myArray)
{
if ([anObject respondsToSelector:@selector(@"setToBlue")])
[anObject setToBlue];
}
La otra cosa acerca de los delegados es que no se retienen, por lo que siempre debe establecer el delegado nil
en su MyClass dealloc
método.
Como una buena práctica recomendada por Apple, es bueno para el delegado (que es un protocolo, por definición), cumplir con el NSObject
protocolo.
@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 @optional
anotación de esta manera:
@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
Por lo tanto, cuando use métodos que haya especificado como opcionales, debe verificar (en su clase) respondsToSelector
si la vista (que se ajusta a su delegado) realmente ha implementado sus métodos opcionales o no.
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 eso, lenguajes de procedimientos como Fortran, etc., así que aquí están mis 2 minutos para encontrar análogos similares en el paradigma de C ++.
Si tuviera que explicar 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 están "delegadas" (en el mundo C ++ - 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 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 trató de 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 debe mantenerse dentro del código y será torpe y propenso a errores. El objetivo C simplemente supone que los programadores no son los mejores para mantener esta declinación y proporciona restricciones del compilador para exigir una implementación limpia.
Un delegado es solo una clase que hace algo de trabajo para otra clase. Lea el siguiente código para obtener un ejemplo de Playground algo tonto (pero con suerte esclarecedor) 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 real, los delegados se usan a menudo en las siguientes situaciones
Las clases no necesitan saber de antemano, excepto que la clase delegada se ajusta al protocolo requerido.
Recomiendo leer los siguientes dos artículos. Me ayudaron a entender a los delegados incluso mejor que la documentación .
Ok, esta no es realmente una respuesta a la pregunta, pero si 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 se comunique / pase datos de una manera, es mucho mejor que con las notificaciones.
NSNotification puede pasar objetos a más de un destinatario y es muy fácil de usar. Funciona así:
El archivo MyClass.m debería verse así
#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: Agregue la clase como observador:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];
Implemente 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];
}
supongamos que tiene una clase que desarrolló y desea declarar una propiedad delegada para poder notificarla cuando ocurra 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
así que declara un protocolo en el MyClass
archivo de encabezado (o un archivo de encabezado separado) y declara los controladores de eventos requeridos / opcionales que su delegado debe / debe implementar, luego declara una propiedad MyClass
de tipo ( id< MyClassDelegate>
) que significa cualquier clase de objetivo c que se ajuste a En el protocolo MyClassDelegate
, notará que la propiedad del delegado se declara débil, esto es muy importante para evitar el ciclo de retención (la mayoría de las veces el delegado retiene la MyClass
instancia, por lo que si declara al delegado como retener, ambos se retendrán entre sí y ninguno de ellos serán lanzados alguna vez).
también notará que los métodos de protocolo pasan la MyClass
instancia 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 MyClass
instancia y también ayuda cuando el delegado se declara MyClassDelegate
en varias MyClass
instancias, como cuando tiene múltiples UITableView's
instancias en tu ViewController
y se declara como una UITableViewDelegate
para todos ellos.
y dentro de MyClass
usted notifica al delegado con los eventos declarados de la siguiente manera:
if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
primero verifica 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).
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 UIViewController< As the protocol I am going to use is UIViewController class>.
Paso: 1: Cree una nueva clase de protocolo llamada "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 de la siguiente manera:
#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 del delegado
#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 se ha definido antes de llamarlo
- (void) someMethodToCallDelegate {
if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
[self.delegate delegateMethodName:self];
}
}
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 el delegado o los métodos de delegado.
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, una vez completada la tarea, se llaman los métodos del delegado.
@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 estableciendo el delegado en sí mismo. Y también el protocolo se implementa en la clase de encabezado.
@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, el control volverá una vez que se complete la operación / tarea.
Descargo de responsabilidad: esta es la Swift
versión de cómo crear un delegate
.
Entonces, ¿qué son los delegados? … En el desarrollo de software, existen arquitecturas de soluciones reutilizables generales que ayudan a resolver problemas comunes 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 que un objeto A llama a un objeto B para realizar una acción. Una vez que se completa la acción, 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, le mostraré cómo crear un delegado personalizado que pase datos entre clases, con Swift en una aplicación simple, comience descargando o clonando este proyecto inicial y ejecútelo.
Puedes ver una aplicación con dos clases, ViewController A
y ViewController B
. B tiene dos vistas que al tocar cambian el color de fondo del ViewController
, nada demasiado complicado ¿verdad? bueno, ahora pensemos de una manera fácil para cambiar también el color de fondo de la clase A cuando se tocan las vistas de la clase B.
El problema es que estas vistas son parte de la clase B y no tienen idea de la clase A, por lo que necesitamos encontrar una manera de comunicarnos 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.
Paso 1: busque el paso 1 de la marca pragma 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 la clase B, dentro del protocolo puede crear tantas funciones como desee según los requisitos de su implementación. En este caso, solo tenemos una función simple que acepta un opcional UIColor
como argumento. Es una buena práctica nombrar sus protocolos agregando la palabra delegate
al final del nombre de la clase, en este caso ClassBVCDelegate
,.
paso 2: busca la marca pragma en el paso 2 ClassVBC
y agrega esto
//MARK: step 2 Create a delegate property here.
weak var delegate: ClassBVCDelegate?
Aquí solo creamos una propiedad delegada para la clase, esta propiedad debe adoptar el protocol
tipo 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 pérdidas de memoria, si no sabe lo que eso significa, no se preocupe por ahora, solo recuerde agregar esta palabra clave.
Paso 3: Busque la marca de paso pragma 3 dentro de la handleTap method
en ClassBVC
y añade este
//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 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 bloqueará incluso si el delegado aún no existe. Vayamos ahora al ClassAVC
archivo y hagámoslo , el delegado.
paso 4: busca la marca de pragma paso 4 dentro del método handleTap ClassAVC
y agrega esto al lado de tu tipo de clase de esta manera.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
Ahora ClassAVC adoptó el ClassBVCDelegate
protocolo, puede ver que su compilador le está dando un error que dice "Escriba 'ClassAVC no se ajusta al protocolo' ClassBVCDelegate 'y esto solo significa que aún no usó 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 me adopte DEBE usar mis funciones!"
Nota rápida: si vienes de un Objective-C
fondo 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, el Swift
idioma no es opcional protocols
, si quieres hacerlo puedes crear una extensión para usted protocol
o use la palabra clave @objc en su protocol
implementación.
Personalmente, si tengo que crear un protocolo con diferentes métodos opcionales, preferiría dividirlo en otro protocols
, de esa manera seguiré el concepto de dar una sola responsabilidad a mis objetos, pero puede variar según la implementación específica.
Aquí hay un buen artículo sobre métodos opcionales.
paso 5: busca la marca pragma paso 5 dentro del método de preparación para el seguimiento y agrega 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 ClassBVC
y asignamos su delegado a self, pero ¿qué es self aquí? bueno, yo es el ClassAVC
que ha sido delegado!
paso 6: Finalmente, busque el pragma paso 6 ClassAVC
y usemos las funciones de protocol
, comience a escribir func changeBackgroundColor y verá que se completa 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 ejecuta la aplicación!
Delegates
están en todas partes y probablemente los use sin previo aviso, si crea una tableview
delegación en el pasado, usó muchas clases de UIKIT
trabajos a su alrededor y muchos otros frameworks
también, resuelven estos problemas principales.
Enhorabuena, acabas de implementar un delegado personalizado, sé que probablemente estás pensando, ¿tantos problemas solo por esto? bueno, la delegación es un patrón de diseño muy importante para entender si quieres convertirte en iOS
desarrollador, y siempre ten en cuenta que tienen una relación uno a uno entre los objetos.
Puedes ver el tutorial original aquí.
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
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{
}
Desde mi punto de vista, crea una clase separada para ese método de delegado y puedes usarla donde quieras.
en mi Custom DropDownClass.h
typedef enum
{
DDSTATE,
DDCITY
}DropDownType;
@protocol DropDownListDelegate <NSObject>
@required
- (void)dropDownDidSelectItemWithString:(NSString*)itemString DropDownType:(DropDownType)dropDownType;
@end
@interface DropDownViewController : UIViewController
{
BOOL isFiltered;
}
@property (nonatomic, assign) DropDownType dropDownType;
@property (weak) id <DropDownListDelegate> delegate;
@property (strong, nonatomic) NSMutableArray *array1DropDown;
@property (strong, nonatomic) NSMutableArray *array2DropDown;
después de ese archivo in.m 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 de delegado personalizado. Después de eso, puede usar este método de delegado donde lo desee. Por ejemplo ...
en mi otra importación viewcontroller después de eso
crear acción para llamar al método delegado como este
- (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 ese método delegado de llamada 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;
}
}
Delegado: - Crear
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
Enviar y asignar delegado para ver que está enviando datos
[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. Implemente el método en la clase .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);
}
Comencemos con un ejemplo, si compramos un producto en línea, pasa por un proceso como el envío / entrega manejado por diferentes equipos. Entonces, si el envío se completa, el equipo de envío debe notificar al equipo de entrega y debe ser una comunicación uno a uno cuando se transmite esta información sería una sobrecarga para otras personas / proveedores que deseen transmitir esta información solo a las personas requeridas.
Entonces, 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í hay un código que considera 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
//
}
}