Un delegado de Objective-C es un objeto que ha sido asignado a la delegatepropiedad 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:
Por UIWebViewotro 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.
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).
Hacer delegados para tus clases
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í:
@protocolUIWebViewDelegate<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, UIWebViewDelegateen este caso. Los implementadores delegados tendrían que adoptar este protocolo:
@interfaceMyClass<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.
Nombrar
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.
Optimizaciones de velocidad
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:
Luego, en el cuerpo, podemos verificar que nuestro delegado maneja los mensajes accediendo a nuestra delegateRespondsToestructura, en lugar de enviarlos -respondsToSelector:una y otra vez.
Delegados informales
Antes de que existieran los protocolos, era común el uso de una categoría en la NSObjectque declare los métodos delegado podría implementar. Por ejemplo, CALayertodavía hace esto:
@interfaceNSObject(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 delegatepropiedad, 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.
Creo que necesita convertir el unsigned inttipo a BOOLcomo el valor de retorno de delegate respondsToSelectores de tipo BOOL.
Roland
¿Se puede usar delegado para polimorfismo como en C ++?
@ Dan Sí, claro. Los protocolos en general se usan para el polimorfismo.
Jesse Rusak
@JesseRusak Creo que "JSSomethingDelegate" debería ser "SomethingDelegate" por coherencia :)
Hans Knöchel
382
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>@classMyClass;//define class, so protocol can see MyClass@protocolMyClassDelegate<NSObject>//define delegate protocol-(void) myClassDelegateMethod:(MyClass*) sender;//define delegate method to be implemented within another class@end//end protocol@interfaceMyClass:NSObject{}@property(nonatomic, weak) id <MyClassDelegate>delegate;//define MyClassDelegate as delegate@end
El archivo MyClass.m debería verse así
#import "MyClass.h"@implementationMyClass@synthesizedelegate;//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"@interfaceMyVC: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!");}
Es genial usar esta respuesta como referencia rápida. Pero, ¿por qué la propiedad delegada en su MyClass.h está marcada como 'IBOutlet'?
Arno van der Meer
44
@ArnovanderMeer ¡Buena captura! No recuerdo por qué. Lo necesito en mi proyecto pero no en este ejemplo, lo eliminé. thx
Tibidabo
Gracias. Tan agradable y exhaustiva como es la respuesta aceptada, aprendo mejor de algún código de muestra compacto. Es bueno tener dos respuestas.
sudo
@Tibidabo Totalmente excepcional. Realmente desearía que todos pudieran explicar conceptos de programación como este. ¡He visto cientos de explicaciones, sobre 'delegados', a lo largo de los años y nunca he entendido esta teoría hasta ahora! Muchas gracias ...
Charles Robertson
55
¿Dónde se myClassinstancia dentro de MyVC.m?
Lane Rettig
18
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.
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 NSWindowquiere llamar a su objeto: solo usa el respondsToSelectormé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 NSArrayde 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 setToBluea 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 nilen su MyClass deallocmétodo.
Como una buena práctica recomendada por Apple, es bueno para el delegado (que es un protocolo, por definición), cumplir con el NSObjectprotocolo.
@protocolMyDelegate<NSObject>...@end
& para crear métodos opcionales dentro de su delegado (es decir, métodos que no necesariamente deben implementarse), puede usar la @optionalanotación de esta manera:
@protocolMyDelegate<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) respondsToSelectorsi 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.
De lo que estás hablando es de semántica mientras yo hablaba de la intuición. De lo que estás hablando es de la función virtual, pero solo acostumbrarte a la nueva terminología puede ser un desafío. La respuesta sirve a los principiantes que quieran pensar en un paralell en C ++ / C
DrBug
Lo que dices no está muy claro para mí. ¿Por qué no escribe una nueva respuesta y veamos si más personas la encuentran útil, la votarán?
DrBug
9
Versión rápida
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}classBossyBigBrother{// 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.returndelegate?.getYourNiceOlderSiblingAGlassOfWater()}}// PoorLittleSister conforms to the OlderSiblingDelegate protocolclassPoorLittleSister: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
Cuando una clase necesita comunicar alguna información a otra clase
Cuando una clase quiere permitir que otra clase lo personalice
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"@implementationMyClass-(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:
-(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 wantNSArray*otherClassData =[note userInfo][@"myClassData"];//get myClass data object and do whatever you want with it}
así que declara un protocolo en el MyClassarchivo 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 MyClassde 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 MyClassinstancia, 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 MyClassinstancia 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 MyClassinstancia y también ayuda cuando el delegado se declara MyClassDelegateen varias MyClassinstancias, como cuando tiene múltiples UITableView'sinstancias en tu ViewControllery se declara como una UITableViewDelegatepara todos ellos.
y dentro de MyClassusted notifica al delegado con los eventos declarados de la siguiente manera:
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).
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>@classYourViewController;@protocolYourViewControllerDelegate<NSObject>@optional-(void)defineDelegateMethodName:(YourViewController*) controller;@required-(BOOL)delegateMethodReturningBool:(YourViewController*) controller;@end@interfaceYourViewController: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<YourViewControllerDelegate>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"@interfaceYourDelegateUser()<YourViewControllerDelegate>@end@implementationYourDelegateUser-(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 herereturn YES;}@end
// prueba si el método se ha definido antes de llamarlo
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:
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.
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.
Descargo de responsabilidad: esta es la Swiftversió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!
Puedes ver una aplicación con dos clases, ViewController Ay 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
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 UIColorcomo argumento. Es una buena práctica nombrar sus protocolos agregando la palabra delegateal final del nombre de la clase, en este caso ClassBVCDelegate,.
paso 2: busca la marca pragma en el paso 2 ClassVBCy 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 protocoltipo 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 methoden ClassBVCy 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 ClassAVCarchivo y hagámoslo , el delegado.
paso 4: busca la marca de pragma paso 4 dentro del método handleTap ClassAVCy agrega esto al lado de tu tipo de clase de esta manera.
//MARK: step 4 conform the protocol here.classClassAVC:UIViewController,ClassBVCDelegate{}
Ahora ClassAVC adoptó el ClassBVCDelegateprotocolo, 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-Cfondo 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 Swiftidioma no es opcional protocols, si quieres hacerlo puedes crear una extensión para usted protocolo use la palabra clave @objc en su protocolimplementació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 ClassBVCy asignamos su delegado a self, pero ¿qué es self aquí? bueno, yo es el ClassAVCque ha sido delegado!
paso 6: Finalmente, busque el pragma paso 6 ClassAVCy 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!
Delegatesestán en todas partes y probablemente los use sin previo aviso, si crea una tableviewdelegación en el pasado, usó muchas clases de UIKITtrabajos a su alrededor y muchos otros frameworkstambién, resuelven estos problemas principales.
Evite el acoplamiento apretado de objetos.
Modifique el comportamiento y la apariencia sin la necesidad de subclasificar objetos.
Permita que las tareas se manejen a cualquier objeto arbitrario.
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 iOSdesarrollador, y siempre ten en cuenta que tienen una relación uno a uno entre los objetos.
La respuesta es realmente respondida, pero me gustaría darle una "hoja de trucos" para crear un delegado:
DELEGATE SCRIPT
CLASS A -Wheredelegate is calling function
@protocol<#ProtocolName#> <NSObject>-(void)delegateMethod;@end@interface<#SomeViewController#> : <#UIViewController#> @property(nonatomic, assign) id <<#ProtocolName#>> delegate;@end@implementation<#SomeViewController#> -(void)someMethod {[self.delegate methodName];}@end
CLASS B -Wheredelegate is called
@interface<#OtherViewController#> (<#Delegate Name#>) {}@end@implementation<#OtherViewController#> -(void)otherMethod {
CLASSA *classA =[[CLASSA alloc] init];[classA setDelegate:self];}-delegateMethod(){}@end
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
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;}}
//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@interfaceMyClassUsesDelegate()<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 productsclassShippingView:UIView{
weak var delegate:ShippingDelegate?
var productID :String@IBAction func checkShippingStatus(sender:UIButton){// if product is shippeddelegate?.productShipped(productID: productID)}}//Delivery view which shows delivery status & tracking infoclassDeliveryView: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 statusclassProductViewController: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
//}}
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 elwebViewDidStartLoad:
método de su delegado , puede crear una clase como esta:Luego, podría crear una instancia de MyClass y asignarla como delegado de la vista web:
Por
UIWebView
otro lado, probablemente tenga un código similar a este para ver si el delegado responde alwebViewDidStartLoad:
mensaje utilizandorespondsToSelector:
y lo envía si corresponde.La propiedad del delegado en sí se suele declarar
weak
(en ARC) oassign
(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).Hacer delegados para tus clases
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í:
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: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.Nombrar
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 deloadStarted
(sin tomar parámetros), por ejemplo.Optimizaciones de velocidad
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:
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.Delegados informales
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: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 ladelegate
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 contaminaNSObject
(lo que hace que el autocompletado sea menos útil) y dificulta que el compilador le advierta sobre errores tipográficos y errores similares.fuente
unsigned int
tipo aBOOL
como el valor de retorno dedelegate respondsToSelector
es de tipoBOOL
.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!)
El archivo MyClass.m debería verse así
Para usar su delegado en otra clase (UIViewController llamado MyVC en este caso) MyVC.h:
MyVC.m:
Implementar método delegado
fuente
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:
en su código de acceso delegado (setDelegate). Esto ayuda a minimizar los errores.
fuente
¡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)
fuente
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 elrespondsToSelector
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 llamarsetToBlue
a los 18 que lo necesitan, algo como esto:La otra cosa acerca de los delegados es que no se retienen, por lo que siempre debe establecer el delegado
nil
en suMyClass dealloc
método.fuente
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.& 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: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.fuente
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.
fuente
Versión rápida
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.
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 .
fuente
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í
Para usar su notificación en otras clases: Agregue la clase como observador:
Implemente el selector:
No olvides eliminar tu clase como observador si
fuente
supongamos que tiene una clase que desarrolló y desea declarar una propiedad delegada para poder notificarla cuando ocurra algún evento:
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 propiedadMyClass
de tipo (id< MyClassDelegate>
) que significa cualquier clase de objetivo c que se ajuste a En el protocoloMyClassDelegate
, 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 laMyClass
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 laMyClass
instancia y también ayuda cuando el delegado se declaraMyClassDelegate
en variasMyClass
instancias, como cuando tiene múltiplesUITableView's
instancias en tuViewController
y se declara como unaUITableViewDelegate
para todos ellos.y dentro de
MyClass
usted notifica al delegado con los eventos declarados de la siguiente manera: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).
fuente
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:
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
// prueba si el método se ha definido antes de llamarlo
fuente
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:
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.
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.
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.
fuente
Descargo de responsabilidad: esta es la
Swift
versión de cómo crear undelegate
.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
yViewController B
. B tiene dos vistas que al tocar cambian el color de fondo delViewController
, 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
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 opcionalUIColor
como argumento. Es una buena práctica nombrar sus protocolos agregando la palabradelegate
al final del nombre de la clase, en este casoClassBVCDelegate
,.paso 2: busca la marca pragma en el paso 2
ClassVBC
y agrega estoAquí 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
enClassBVC
y añade esteUna 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.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, elSwift
idioma no es opcionalprotocols
, si quieres hacerlo puedes crear una extensión para ustedprotocol
o use la palabra clave @objc en suprotocol
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
Aquí solo estamos creando una instancia
ClassBVC
y asignamos su delegado a self, pero ¿qué es self aquí? bueno, yo es elClassAVC
que ha sido delegado!paso 6: Finalmente, busque el pragma paso 6
ClassAVC
y usemos las funciones deprotocol
, 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.Ahora ejecuta la aplicación!
Delegates
están en todas partes y probablemente los use sin previo aviso, si crea unatableview
delegación en el pasado, usó muchas clases deUIKIT
trabajos a su alrededor y muchos otrosframeworks
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í.
fuente
La respuesta es realmente respondida, pero me gustaría darle una "hoja de trucos" para crear un delegado:
fuente
ViewController.h
ViewController.m
MainViewController.m
Método:
fuente
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
después de ese archivo in.m crear matriz con objetos,
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
después de ese método delegado de llamada como este
fuente
Delegado: - Crear
Enviar y asignar delegado para ver que está enviando datos
fuente
// 5. Implemente el método en la clase .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);
}
fuente
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:
fuente