Um delegado do Objective-C é um objeto que foi atribuído à delegatepropriedade outro objeto. Para criar um, defina uma classe que implemente os métodos de delegação de seu interesse e marque essa classe como implementando o protocolo de delegação.
Por exemplo, suponha que você tenha um UIWebView. Se você deseja implementar o webViewDidStartLoad:método de seu representante , você pode criar uma classe como esta:
Por UIWebViewoutro lado, provavelmente possui um código semelhante a este para verificar se o delegado responde à webViewDidStartLoad:mensagem usando respondsToSelector:e enviá-lo, se apropriado.
A propriedade delegada em si normalmente é declarada weak(no ARC) ouassign (pré-ARC) para evitar loops de retenção, uma vez que o delegado de um objeto geralmente mantém uma forte referência a esse objeto. (Por exemplo, um controlador de exibição geralmente é o delegado de uma exibição que contém.)
Como fazer delegados para suas aulas
Para definir seus próprios delegados, você precisará declarar seus métodos em algum lugar, conforme discutido no Apple Docs sobre protocolos . Você geralmente declara um protocolo formal. A declaração, parafraseada em UIWebView.h, ficaria assim:
@protocolUIWebViewDelegate<NSObject>@optional-(void)webViewDidStartLoad:(UIWebView*)webView;// ... other methods here@end
Isso é análogo a uma interface ou classe base abstrata, pois cria um tipo especial para o seu delegado, UIWebViewDelegateneste caso. Os implementadores delegados teriam que adotar este protocolo:
@interfaceMyClass<UIWebViewDelegate>// ...@end
E, em seguida, implemente os métodos no protocolo. Para métodos declarados no protocolo como @optional(como a maioria dos métodos delegados), é necessário verificar -respondsToSelector:antes de chamar um método específico.
Nomeação
Os métodos de delegação geralmente são nomeados começando com o nome da classe de delegação e tomam o objeto de delegação como o primeiro parâmetro. Eles também costumam usar uma forma de vontade, deveria ou didática. Portanto, webViewDidStartLoad:(o primeiro parâmetro é a visualização da web) e não loadStarted(sem parâmetros), por exemplo.
Otimizações de velocidade
Em vez de verificar se um delegado responde a um seletor toda vez que desejamos enviá-lo por mensagem, você pode armazenar em cache essas informações quando os delegados estiverem definidos. Uma maneira muito limpa de fazer isso é usar um campo de bits, da seguinte maneira:
Então, no corpo, podemos verificar se nosso delegado lida com mensagens acessando nossa delegateRespondsToestrutura, em vez de enviar -respondsToSelector:repetidas vezes.
Delegados informais
Antes de protocolos existia, era comum usar uma categoria de NSObjectdeclarar os métodos de um delegado poderia implementar. Por exemplo, CALayerainda faz isso:
@interfaceNSObject(CALayerDelegate)-(void)displayLayer:(CALayer*)layer;// ... other methods here@end
Isso informa ao compilador que qualquer objeto pode implementar displayLayer:.
Você usaria a mesma -respondsToSelector:abordagem descrita acima para chamar esse método. Os delegados implementam esse método e atribuem a delegatepropriedade, e é isso (não há como declarar que você está em conformidade com um protocolo). Esse método é comum nas bibliotecas da Apple, mas o novo código deve usar a abordagem de protocolo mais moderna acima, uma vez que essa abordagem polui NSObject(o que torna o preenchimento automático menos útil) e dificulta o compilador avisá-lo sobre erros de digitação e erros semelhantes.
Acho que você precisa para lançar o unsigned inttipo de BOOLcomo o valor de retorno delegate respondsToSelectoré do tipo BOOL.
Roland
O delegado pode ser usado para polimorfismo, como em C ++?
@ Dan Sim, com certeza. Protocolos em geral são usados para polimorfismo.
Jesse Rusak
@JesseRusak eu penso "JSSomethingDelegate" deve ser "SomethingDelegate" para a consistência :)
Hans Knöchel
382
A resposta aprovada é ótima, mas se você estiver procurando por uma resposta de 1 minuto, tente o seguinte:
O arquivo MyClass.h deve ficar assim (adicione linhas de delegado com comentários!)
#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
O arquivo MyClass.m deve ficar assim
#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 seu representante em outra classe (neste caso, UIViewController chamado MyVC) 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!");}
É ótimo usar essa resposta como uma referência rápida. Mas por que a propriedade delegate no seu MyClass.h está marcada como 'IBOutlet'?
Arno van der Meer
4
@ArnovanderMeer Good catch! Não me lembro por quê. Eu preciso dele no meu projeto, mas não neste exemplo, eu o removi. thx
Tibidabo
Obrigado. Por mais agradável e completa que seja a resposta aceita, aprendo melhor com alguns exemplos de códigos compactos. É bom ter duas respostas.
Sudo
@Tibidabo Totalmente excelente. Eu realmente gostaria que todos pudessem explicar conceitos de programação como este. Eu tenho visto centenas de explicações, sobre 'delegados', ao longo dos anos e nunca realmente compreendi essa teoria até agora! Muito obrigado ...
Charles Robertson
5
Onde é myClassinstanciado dentro do MyVC.m?
Lane Rettig
18
Ao usar o método formal de protocolo para criar suporte ao delegado, descobri que você pode garantir a verificação adequada do tipo (embora, tempo de execução, sem tempo de compilação) adicionando algo como:
if(![delegate conformsToProtocol:@protocol(MyDelegate)]){[NSException raise:@"MyDelegate Exception"
format:@"Parameter does not conform to MyDelegate protocol at line %d",(int)__LINE__];}
no código do acessador delegado (setDelegate). Isso ajuda a minimizar erros.
Se você vem de um ponto de vista semelhante ao C ++, os delegados demoram um pouco para se acostumar - mas basicamente 'eles simplesmente funcionam'.
O modo como funciona é que você defina algum objeto que você escreveu como delegado para o NSWindow, mas seu objeto possui apenas implementações (métodos) para um ou alguns dos muitos métodos possíveis de delegação. Então, algo acontece e NSWindowdeseja chamar seu objeto - ele apenas usa o respondsToSelectormétodo de Objective-c para determinar se seu objeto deseja que esse método seja chamado e depois o chama. É assim que o objetivo-c funciona - os métodos são pesquisados sob demanda.
É totalmente trivial fazer isso com seus próprios objetos; não há nada de especial; você pode, por exemplo, ter um NSArrayde 27 objetos, todos os tipos de objetos, apenas 18 deles com o método -(void)setToBue;Os outros 9 não. Então, para chamar setToBluetodos os 18 que precisam, algo assim:
for(id anObject in myArray){if([anObject respondsToSelector:@selector(@"setToBlue")])[anObject setToBlue];}
A outra coisa sobre os delegados é que eles não são retidos; portanto, você sempre deve definir o delegado nilno seu MyClass deallocmétodo.
Como boa prática recomendada pela Apple, é bom que o delegado (que é um protocolo, por definição), esteja em conformidade com o NSObjectprotocolo.
@protocolMyDelegate<NSObject>...@end
& para criar métodos opcionais dentro do seu delegado (ou seja, métodos que não precisam necessariamente ser implementados), você pode usar a @optionalanotação da seguinte maneira:
@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
Portanto, ao usar métodos que você especificou como opcionais, é necessário (em sua classe) verificar respondsToSelectorse a exibição (que está em conformidade com seu delegado) realmente implementou seus métodos opcionais ou não.
Acho que todas essas respostas fazem muito sentido depois que você entende os delegados. Pessoalmente, eu vim da terra do C / C ++ e, antes disso, linguagens procedurais como Fortran, etc.
Se eu explicasse os delegados a um programador C ++ / Java, eu diria
O que são delegados? Esses são indicadores estáticos para classes dentro de outra classe. Depois de atribuir um ponteiro, você pode chamar funções / métodos nessa classe. Portanto, algumas funções da sua classe são "delegadas" (no mundo C ++ - ponteiro para por um ponteiro de objeto de classe) para outra classe.
O que são protocolos? Conceitualmente, serve para uma finalidade semelhante ao arquivo de cabeçalho da classe que você está atribuindo como uma classe delegada. Um protocolo é uma maneira explícita de definir quais métodos precisam ser implementados na classe cujo ponteiro foi definido como delegado dentro de uma classe.
Como posso fazer algo semelhante em C ++? Se você tentou fazer isso em C ++, definiu ponteiros para classes (objetos) na definição de classe e os conectou a outras classes que fornecerão funções adicionais como delegadas à sua classe base. Mas essa fiação precisa ser mantida dentro do código e será desajeitada e propensa a erros. O objetivo C apenas supõe que os programadores não são os melhores em manter essa deciplina e fornece restrições ao compilador para impor uma implementação limpa.
O que você está falando é semântica enquanto eu estava falando sobre a intuição. O que você está falando é sobre função virtual - mas apenas para se acostumar com a nova terminologia pode ser um desafio. A resposta serve beginers que querem pensar em um paralelo em C ++ / C
DrBug
O que você está dizendo não é realmente claro para mim. Por que você não escreve uma nova resposta e deixa ver se mais pessoas a acham útil, elas votarão nela?
DrBug
9
Versão Swift
Um delegado é apenas uma classe que trabalha para outra classe. Leia o código a seguir para obter um exemplo parvo (mas esperançosamente esclarecedor) do Playground, que mostra como isso é feito no 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!"}
Na prática, os delegados são frequentemente usados nas seguintes situações
Quando uma classe precisa comunicar algumas informações para outra classe
Quando uma classe deseja permitir que outra classe a personalize
As classes não precisam saber nada uma sobre a outra, exceto que a classe delegada está em conformidade com o protocolo necessário.
Eu recomendo a leitura dos dois artigos a seguir. Eles me ajudaram a entender os delegados ainda melhor do que a documentação .
Ok, isso não é realmente uma resposta para a pergunta, mas se você está procurando saber como fazer seu próprio delegado, talvez algo muito mais simples possa ser uma resposta melhor para você.
Mal implemento meus delegados porque raramente preciso. Eu posso ter APENAS UM delegado para um objeto delegado. Portanto, se você deseja que seu delegado receba uma comunicação unidirecional / transmissão de dados, é melhor que ele receba notificações.
O NSNotification pode passar objetos para mais de um destinatário e é muito fácil de usar. Funciona assim:
O arquivo MyClass.m deve ficar assim
#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 sua notificação em outras classes: Adicione a classe como um 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}
Não se esqueça de remover sua classe como observador se
digamos que você tenha uma classe que você desenvolveu e deseja declarar uma propriedade delegada para poder notificá-la quando algum evento acontecer:
para que você declare um protocolo no MyClassarquivo de cabeçalho (ou um arquivo de cabeçalho separado) e declare os manipuladores de eventos opcionais / obrigatórios que seu delegado deve / deve implementar e, em seguida, declare uma propriedade no MyClasstipo ( id< MyClassDelegate>) que significa qualquer classe c objetiva que esteja em conformidade com o protocolo MyClassDelegate, você notará que a propriedade delegate é declarada fraca, isso é muito importante para evitar o ciclo de retenção (na maioria das vezes o delegado retém a MyClassinstância, portanto, se você declarou o delegado como retido, os dois reterão um ao outro e nenhum deles será lançado).
você notará também que os métodos de protocolo transmitem a MyClassinstância ao delegado como parâmetro, essa é uma prática recomendada caso o delegado queira chamar alguns métodos na MyClassinstância e também ajuda quando o delegado se declara MyClassDelegateem várias MyClassinstâncias, como quando você tem várias UITableView'sinstâncias no seu ViewControllere se declara como um UITableViewDelegatepara todos eles.
e dentro do seu, MyClassvocê notifica o delegado com eventos declarados da seguinte maneira:
verifique primeiro se o delegado responde ao método de protocolo que você está prestes a chamar, caso o delegado não o implemente e o aplicativo trava (mesmo se o método de protocolo for necessário).
Crie o protocolo no arquivo .h. Certifique-se de que esteja definido antes do protocolo usando @class seguido pelo nome do UIViewController< As the protocol I am going to use is UIViewController class>.
Etapa: 1: Crie um novo protocolo de classe chamado "YourViewController", que será a subclasse da classe UIViewController e atribua essa classe ao segundo ViewController.
Etapa: 2: Vá para o arquivo "YourViewController" e modifique-o conforme abaixo:
#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
Os métodos definidos no comportamento do protocolo podem ser controlados com @optional e @required como parte da definição do protocolo.
Etapa: 3: Implementação do 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
// teste se o método foi definido antes de chamá-lo
Para criar seu próprio delegado, primeiro você precisa criar um protocolo e declarar os métodos necessários, sem implementar. E, em seguida, implemente esse protocolo na classe de cabeçalho em que deseja implementar os métodos delegar ou delegar.
Esta é a classe de serviço em que alguma tarefa deve ser realizada. Ele mostra como definir delegado e como definir o delegado. Na classe de implementação, após a conclusão da tarefa, os métodos do delegado são chamados.
Essa é a classe de exibição principal de onde a classe de serviço é chamada, configurando o delegado para si mesmo. E também o protocolo é implementado na classe de cabeçalho.
Isenção de responsabilidade: esta é a Swiftversão de como criar um delegate.
Então, o que são delegados? … No desenvolvimento de software, existem arquiteturas de soluções reutilizáveis gerais que ajudam a resolver problemas comuns em um determinado contexto, esses “modelos”, por assim dizer, são mais conhecidos como padrões de design. Delegados são um padrão de design que permite que um objeto envie mensagens para outro objeto quando um evento específico acontece. Imagine um objeto A chama um objeto B para executar uma ação. Depois que a ação estiver concluída, o objeto A deve saber que B concluiu a tarefa e tomar as medidas necessárias, isso pode ser alcançado com a ajuda dos delegados!
Você pode ver um aplicativo com duas classes ViewController Ae ViewController B. B tem duas visualizações que na torneira mudam a cor de fundo do ViewController, nada muito complicado, certo? bem, agora vamos pensar de uma maneira fácil de alterar também a cor de fundo da classe A quando as visualizações na classe B são tocadas.
O problema é que essas visualizações fazem parte da classe B e não têm idéia da classe A, portanto, precisamos encontrar uma maneira de se comunicar entre essas duas classes, e é aí que brilha a delegação. Dividi a implementação em 6 etapas para que você possa usar isso como uma folha de dicas quando precisar.
etapa 1: procure a marca de pragma etapa 1 no arquivo ClassBVC e adicione este
O primeiro passo é criar um protocol, neste caso, criaremos o protocolo na classe B, dentro do protocolo, você poderá criar quantas funções desejar com base nos requisitos de sua implementação. Nesse caso, temos apenas uma função simples que aceita um opcional UIColorcomo argumento. É uma boa prática nomear seus protocolos adicionando a palavra delegateno final do nome da classe, neste caso ClassBVCDelegate,.
etapa 2: procure a marca de pragma etapa 2 ClassVBCe adicione este
//MARK: step 2 Create a delegate property here.
weak var delegate:ClassBVCDelegate?
Aqui, apenas criamos uma propriedade delegada para a classe, essa propriedade deve adotar o protocoltipo e deve ser opcional. Além disso, você deve adicionar a palavra-chave fraca antes da propriedade para evitar reter ciclos e possíveis vazamentos de memória. Se você não sabe o que isso significa, não se preocupe, lembre-se de adicionar essa palavra-chave.
etapa 3: procure a marca de pragma etapa 3 dentro da alçaToque methodem ClassBVCe adicione este
//MARK: step 3 Add the delegate method call here.delegate?.changeBackgroundColor(tapGesture.view?.backgroundColor)
Uma coisa que você deve saber, executar o aplicativo e tocar em qualquer visualização, não verá nenhum comportamento novo e isso é correto, mas o que quero salientar é que o aplicativo não está travando quando o delegado é chamado e é porque nós o criamos como um valor opcional e é por isso que ele não falha mesmo que o delegado ainda não exista. Vamos agora ClassAVCarquivar e torná-lo, o delegado.
etapa 4: procure a marca de pragma etapa 4 dentro do método handleTap ClassAVCe adicione-a ao lado do seu tipo de classe como este.
//MARK: step 4 conform the protocol here.classClassAVC:UIViewController,ClassBVCDelegate{}
Agora o ClassAVC adotou o ClassBVCDelegateprotocolo, você pode ver que seu compilador está fornecendo um erro que diz “Tipo 'ClassAVC não está em conformidade com o protocolo' ClassBVCDelegate 'e isso significa apenas que você ainda não usou os métodos do protocolo, imagine que quando a classe A adota o protocolo é como assinar um contrato com a classe B e este contrato diz "Qualquer classe que me adote DEVE usar minhas funções!"
Nota rápida: Se você é de Objective-Corigem, provavelmente pensa que também pode calar esse erro, tornando esse método opcional, mas, para minha surpresa e provavelmente a sua, o Swiftidioma não suporta opcional protocols, se você quiser, pode criar uma extensão para você protocolou use a palavra-chave @objc em sua protocolimplementação.
Pessoalmente, se eu tiver que criar um protocolo com diferentes métodos opcionais, prefiro dividi-lo em diferentes protocols, dessa maneira seguirei o conceito de atribuir uma única responsabilidade aos meus objetos, mas isso pode variar com base na implementação específica.
etapa 5: procure a marca de pragma etapa 5 dentro do método prepare for segue e adicione este
//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
}
Aqui estamos apenas criando uma instância ClassBVCe atribuindo seu delegado a si mesmo, mas o que é eu aqui? bem, o eu é o ClassAVCque foi delegado!
passo 6: Finalmente, procure o pragma do passo 6 ClassAVCe vamos usar as funções do protocol, comece a digitar func changeBackgroundColor e você verá que ele é preenchido automaticamente para você. Você pode adicionar qualquer implementação dentro dela, neste exemplo, apenas mudaremos a cor do plano de fundo, adicione isso.
//MARK: step 6 finally use the method of the contract
func changeBackgroundColor(_ color:UIColor?){
view.backgroundColor = color
}
Agora execute o aplicativo!
Delegatesestão em toda parte e você provavelmente as usa sem aviso prévio; se você criou uma tableviewdelegação no passado, usou muitas classes de UIKITtrabalhos ao seu redor e muitas outras frameworkstambém, elas resolvem esses problemas principais.
Evite acoplamentos apertados de objetos.
Modifique o comportamento e a aparência sem a necessidade de subclassificar objetos.
Permitir que tarefas sejam manipuladas para qualquer objeto arbitrário.
Parabéns, você acabou de implementar um delegado personalizado, eu sei que você provavelmente está pensando, tantos problemas só por isso? bem, delegação é um padrão de design muito importante para entender se você deseja se tornar um iOSdesenvolvedor e sempre lembre-se de que eles têm um relacionamento individual entre os objetos.
A resposta é realmente respondida, mas eu gostaria de lhe dar uma "folha de dicas" para criar um 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
-(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 o método na classe .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);
Vamos começar com um exemplo: se comprarmos um produto on-line, ele passará por processos como remessa / entrega manipulados por equipes diferentes. seria uma sobrecarga para outras pessoas / fornecedores que desejam passar essas informações apenas para as pessoas necessárias.
Portanto, se pensarmos em termos de nosso aplicativo, um evento pode ser um pedido on-line e equipes diferentes podem ter várias visualizações.
Aqui está o código considere o ShippingView como equipe de envio e DeliveryView como equipe 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
//}}
Respostas:
Um delegado do Objective-C é um objeto que foi atribuído à
delegate
propriedade outro objeto. Para criar um, defina uma classe que implemente os métodos de delegação de seu interesse e marque essa classe como implementando o protocolo de delegação.Por exemplo, suponha que você tenha um
UIWebView
. Se você deseja implementar owebViewDidStartLoad:
método de seu representante , você pode criar uma classe como esta:Em seguida, você pode criar uma instância do MyClass e atribuí-la como delegada da visualização da web:
Por
UIWebView
outro lado, provavelmente possui um código semelhante a este para verificar se o delegado responde àwebViewDidStartLoad:
mensagem usandorespondsToSelector:
e enviá-lo, se apropriado.A propriedade delegada em si normalmente é declarada
weak
(no ARC) ouassign
(pré-ARC) para evitar loops de retenção, uma vez que o delegado de um objeto geralmente mantém uma forte referência a esse objeto. (Por exemplo, um controlador de exibição geralmente é o delegado de uma exibição que contém.)Como fazer delegados para suas aulas
Para definir seus próprios delegados, você precisará declarar seus métodos em algum lugar, conforme discutido no Apple Docs sobre protocolos . Você geralmente declara um protocolo formal. A declaração, parafraseada em UIWebView.h, ficaria assim:
Isso é análogo a uma interface ou classe base abstrata, pois cria um tipo especial para o seu delegado,
UIWebViewDelegate
neste caso. Os implementadores delegados teriam que adotar este protocolo:E, em seguida, implemente os métodos no protocolo. Para métodos declarados no protocolo como
@optional
(como a maioria dos métodos delegados), é necessário verificar-respondsToSelector:
antes de chamar um método específico.Nomeação
Os métodos de delegação geralmente são nomeados começando com o nome da classe de delegação e tomam o objeto de delegação como o primeiro parâmetro. Eles também costumam usar uma forma de vontade, deveria ou didática. Portanto,
webViewDidStartLoad:
(o primeiro parâmetro é a visualização da web) e nãoloadStarted
(sem parâmetros), por exemplo.Otimizações de velocidade
Em vez de verificar se um delegado responde a um seletor toda vez que desejamos enviá-lo por mensagem, você pode armazenar em cache essas informações quando os delegados estiverem definidos. Uma maneira muito limpa de fazer isso é usar um campo de bits, da seguinte maneira:
Então, no corpo, podemos verificar se nosso delegado lida com mensagens acessando nossa
delegateRespondsTo
estrutura, em vez de enviar-respondsToSelector:
repetidas vezes.Delegados informais
Antes de protocolos existia, era comum usar uma categoria de
NSObject
declarar os métodos de um delegado poderia implementar. Por exemplo,CALayer
ainda faz isso:Isso informa ao compilador que qualquer objeto pode implementar
displayLayer:
.Você usaria a mesma
-respondsToSelector:
abordagem descrita acima para chamar esse método. Os delegados implementam esse método e atribuem adelegate
propriedade, e é isso (não há como declarar que você está em conformidade com um protocolo). Esse método é comum nas bibliotecas da Apple, mas o novo código deve usar a abordagem de protocolo mais moderna acima, uma vez que essa abordagem poluiNSObject
(o que torna o preenchimento automático menos útil) e dificulta o compilador avisá-lo sobre erros de digitação e erros semelhantes.fonte
unsigned int
tipo deBOOL
como o valor de retornodelegate respondsToSelector
é do tipoBOOL
.A resposta aprovada é ótima, mas se você estiver procurando por uma resposta de 1 minuto, tente o seguinte:
O arquivo MyClass.h deve ficar assim (adicione linhas de delegado com comentários!)
O arquivo MyClass.m deve ficar assim
Para usar seu representante em outra classe (neste caso, UIViewController chamado MyVC) MyVC.h:
MyVC.m:
Implementar método delegado
fonte
myClass
instanciado dentro do MyVC.m?Ao usar o método formal de protocolo para criar suporte ao delegado, descobri que você pode garantir a verificação adequada do tipo (embora, tempo de execução, sem tempo de compilação) adicionando algo como:
no código do acessador delegado (setDelegate). Isso ajuda a minimizar erros.
fonte
Por favor! confira abaixo o tutorial passo a passo simples para entender como os delegados funcionam no iOS.
Eu criei dois ViewControllers (para enviar dados de um para outro)
fonte
Talvez isso seja mais do que você está perdendo:
Se você vem de um ponto de vista semelhante ao C ++, os delegados demoram um pouco para se acostumar - mas basicamente 'eles simplesmente funcionam'.
O modo como funciona é que você defina algum objeto que você escreveu como delegado para o NSWindow, mas seu objeto possui apenas implementações (métodos) para um ou alguns dos muitos métodos possíveis de delegação. Então, algo acontece e
NSWindow
deseja chamar seu objeto - ele apenas usa orespondsToSelector
método de Objective-c para determinar se seu objeto deseja que esse método seja chamado e depois o chama. É assim que o objetivo-c funciona - os métodos são pesquisados sob demanda.É totalmente trivial fazer isso com seus próprios objetos; não há nada de especial; você pode, por exemplo, ter um
NSArray
de 27 objetos, todos os tipos de objetos, apenas 18 deles com o método-(void)setToBue;
Os outros 9 não. Então, para chamarsetToBlue
todos os 18 que precisam, algo assim:A outra coisa sobre os delegados é que eles não são retidos; portanto, você sempre deve definir o delegado
nil
no seuMyClass dealloc
método.fonte
Como boa prática recomendada pela Apple, é bom que o delegado (que é um protocolo, por definição), esteja em conformidade com o
NSObject
protocolo.& para criar métodos opcionais dentro do seu delegado (ou seja, métodos que não precisam necessariamente ser implementados), você pode usar a
@optional
anotação da seguinte maneira:Portanto, ao usar métodos que você especificou como opcionais, é necessário (em sua classe) verificar
respondsToSelector
se a exibição (que está em conformidade com seu delegado) realmente implementou seus métodos opcionais ou não.fonte
Acho que todas essas respostas fazem muito sentido depois que você entende os delegados. Pessoalmente, eu vim da terra do C / C ++ e, antes disso, linguagens procedurais como Fortran, etc.
Se eu explicasse os delegados a um programador C ++ / Java, eu diria
O que são delegados? Esses são indicadores estáticos para classes dentro de outra classe. Depois de atribuir um ponteiro, você pode chamar funções / métodos nessa classe. Portanto, algumas funções da sua classe são "delegadas" (no mundo C ++ - ponteiro para por um ponteiro de objeto de classe) para outra classe.
O que são protocolos? Conceitualmente, serve para uma finalidade semelhante ao arquivo de cabeçalho da classe que você está atribuindo como uma classe delegada. Um protocolo é uma maneira explícita de definir quais métodos precisam ser implementados na classe cujo ponteiro foi definido como delegado dentro de uma classe.
Como posso fazer algo semelhante em C ++? Se você tentou fazer isso em C ++, definiu ponteiros para classes (objetos) na definição de classe e os conectou a outras classes que fornecerão funções adicionais como delegadas à sua classe base. Mas essa fiação precisa ser mantida dentro do código e será desajeitada e propensa a erros. O objetivo C apenas supõe que os programadores não são os melhores em manter essa deciplina e fornece restrições ao compilador para impor uma implementação limpa.
fonte
Versão Swift
Um delegado é apenas uma classe que trabalha para outra classe. Leia o código a seguir para obter um exemplo parvo (mas esperançosamente esclarecedor) do Playground, que mostra como isso é feito no Swift.
Na prática, os delegados são frequentemente usados nas seguintes situações
As classes não precisam saber nada uma sobre a outra, exceto que a classe delegada está em conformidade com o protocolo necessário.
Eu recomendo a leitura dos dois artigos a seguir. Eles me ajudaram a entender os delegados ainda melhor do que a documentação .
fonte
Ok, isso não é realmente uma resposta para a pergunta, mas se você está procurando saber como fazer seu próprio delegado, talvez algo muito mais simples possa ser uma resposta melhor para você.
Mal implemento meus delegados porque raramente preciso. Eu posso ter APENAS UM delegado para um objeto delegado. Portanto, se você deseja que seu delegado receba uma comunicação unidirecional / transmissão de dados, é melhor que ele receba notificações.
O NSNotification pode passar objetos para mais de um destinatário e é muito fácil de usar. Funciona assim:
O arquivo MyClass.m deve ficar assim
Para usar sua notificação em outras classes: Adicione a classe como um observador:
Implemente o seletor:
Não se esqueça de remover sua classe como observador se
fonte
digamos que você tenha uma classe que você desenvolveu e deseja declarar uma propriedade delegada para poder notificá-la quando algum evento acontecer:
para que você declare um protocolo no
MyClass
arquivo de cabeçalho (ou um arquivo de cabeçalho separado) e declare os manipuladores de eventos opcionais / obrigatórios que seu delegado deve / deve implementar e, em seguida, declare uma propriedade noMyClass
tipo (id< MyClassDelegate>
) que significa qualquer classe c objetiva que esteja em conformidade com o protocoloMyClassDelegate
, você notará que a propriedade delegate é declarada fraca, isso é muito importante para evitar o ciclo de retenção (na maioria das vezes o delegado retém aMyClass
instância, portanto, se você declarou o delegado como retido, os dois reterão um ao outro e nenhum deles será lançado).você notará também que os métodos de protocolo transmitem a
MyClass
instância ao delegado como parâmetro, essa é uma prática recomendada caso o delegado queira chamar alguns métodos naMyClass
instância e também ajuda quando o delegado se declaraMyClassDelegate
em váriasMyClass
instâncias, como quando você tem váriasUITableView's
instâncias no seuViewController
e se declara como umUITableViewDelegate
para todos eles.e dentro do seu,
MyClass
você notifica o delegado com eventos declarados da seguinte maneira:verifique primeiro se o delegado responde ao método de protocolo que você está prestes a chamar, caso o delegado não o implemente e o aplicativo trava (mesmo se o método de protocolo for necessário).
fonte
Aqui está um método simples para criar delegados
Crie o protocolo no arquivo .h. Certifique-se de que esteja definido antes do protocolo usando @class seguido pelo nome do UIViewController
< As the protocol I am going to use is UIViewController class>.
Etapa: 1: Crie um novo protocolo de classe chamado "YourViewController", que será a subclasse da classe UIViewController e atribua essa classe ao segundo ViewController.
Etapa: 2: Vá para o arquivo "YourViewController" e modifique-o conforme abaixo:
Os métodos definidos no comportamento do protocolo podem ser controlados com @optional e @required como parte da definição do protocolo.
Etapa: 3: Implementação do Delegado
// teste se o método foi definido antes de chamá-lo
fonte
Para criar seu próprio delegado, primeiro você precisa criar um protocolo e declarar os métodos necessários, sem implementar. E, em seguida, implemente esse protocolo na classe de cabeçalho em que deseja implementar os métodos delegar ou delegar.
Um protocolo deve ser declarado como abaixo:
Esta é a classe de serviço em que alguma tarefa deve ser realizada. Ele mostra como definir delegado e como definir o delegado. Na classe de implementação, após a conclusão da tarefa, os métodos do delegado são chamados.
Essa é a classe de exibição principal de onde a classe de serviço é chamada, configurando o delegado para si mesmo. E também o protocolo é implementado na classe de cabeçalho.
É isso e, ao implementar métodos delegados nesta classe, o controle retornará assim que a operação / tarefa for concluída.
fonte
Isenção de responsabilidade: esta é a
Swift
versão de como criar umdelegate
.Então, o que são delegados? … No desenvolvimento de software, existem arquiteturas de soluções reutilizáveis gerais que ajudam a resolver problemas comuns em um determinado contexto, esses “modelos”, por assim dizer, são mais conhecidos como padrões de design. Delegados são um padrão de design que permite que um objeto envie mensagens para outro objeto quando um evento específico acontece. Imagine um objeto A chama um objeto B para executar uma ação. Depois que a ação estiver concluída, o objeto A deve saber que B concluiu a tarefa e tomar as medidas necessárias, isso pode ser alcançado com a ajuda dos delegados!
Para uma explicação melhor, mostrarei como criar um delegado personalizado que transmita dados entre classes, com o Swift em um aplicativo simples, comece baixando ou clonando este projeto inicial e executando-o!
Você pode ver um aplicativo com duas classes
ViewController A
eViewController B
. B tem duas visualizações que na torneira mudam a cor de fundo doViewController
, nada muito complicado, certo? bem, agora vamos pensar de uma maneira fácil de alterar também a cor de fundo da classe A quando as visualizações na classe B são tocadas.O problema é que essas visualizações fazem parte da classe B e não têm idéia da classe A, portanto, precisamos encontrar uma maneira de se comunicar entre essas duas classes, e é aí que brilha a delegação. Dividi a implementação em 6 etapas para que você possa usar isso como uma folha de dicas quando precisar.
etapa 1: procure a marca de pragma etapa 1 no arquivo ClassBVC e adicione este
O primeiro passo é criar um
protocol
, neste caso, criaremos o protocolo na classe B, dentro do protocolo, você poderá criar quantas funções desejar com base nos requisitos de sua implementação. Nesse caso, temos apenas uma função simples que aceita um opcionalUIColor
como argumento. É uma boa prática nomear seus protocolos adicionando a palavradelegate
no final do nome da classe, neste casoClassBVCDelegate
,.etapa 2: procure a marca de pragma etapa 2
ClassVBC
e adicione esteAqui, apenas criamos uma propriedade delegada para a classe, essa propriedade deve adotar o
protocol
tipo e deve ser opcional. Além disso, você deve adicionar a palavra-chave fraca antes da propriedade para evitar reter ciclos e possíveis vazamentos de memória. Se você não sabe o que isso significa, não se preocupe, lembre-se de adicionar essa palavra-chave.etapa 3: procure a marca de pragma etapa 3 dentro da alçaToque
method
emClassBVC
e adicione esteUma coisa que você deve saber, executar o aplicativo e tocar em qualquer visualização, não verá nenhum comportamento novo e isso é correto, mas o que quero salientar é que o aplicativo não está travando quando o delegado é chamado e é porque nós o criamos como um valor opcional e é por isso que ele não falha mesmo que o delegado ainda não exista. Vamos agora
ClassAVC
arquivar e torná-lo, o delegado.etapa 4: procure a marca de pragma etapa 4 dentro do método handleTap
ClassAVC
e adicione-a ao lado do seu tipo de classe como este.Agora o ClassAVC adotou o
ClassBVCDelegate
protocolo, você pode ver que seu compilador está fornecendo um erro que diz “Tipo 'ClassAVC não está em conformidade com o protocolo' ClassBVCDelegate 'e isso significa apenas que você ainda não usou os métodos do protocolo, imagine que quando a classe A adota o protocolo é como assinar um contrato com a classe B e este contrato diz "Qualquer classe que me adote DEVE usar minhas funções!"Nota rápida: Se você é de
Objective-C
origem, provavelmente pensa que também pode calar esse erro, tornando esse método opcional, mas, para minha surpresa e provavelmente a sua, oSwift
idioma não suporta opcionalprotocols
, se você quiser, pode criar uma extensão para vocêprotocol
ou use a palavra-chave @objc em suaprotocol
implementação.Pessoalmente, se eu tiver que criar um protocolo com diferentes métodos opcionais, prefiro dividi-lo em diferentes
protocols
, dessa maneira seguirei o conceito de atribuir uma única responsabilidade aos meus objetos, mas isso pode variar com base na implementação específica.Aqui está um bom artigo sobre métodos opcionais.
etapa 5: procure a marca de pragma etapa 5 dentro do método prepare for segue e adicione este
Aqui estamos apenas criando uma instância
ClassBVC
e atribuindo seu delegado a si mesmo, mas o que é eu aqui? bem, o eu é oClassAVC
que foi delegado!passo 6: Finalmente, procure o pragma do passo 6
ClassAVC
e vamos usar as funções doprotocol
, comece a digitar func changeBackgroundColor e você verá que ele é preenchido automaticamente para você. Você pode adicionar qualquer implementação dentro dela, neste exemplo, apenas mudaremos a cor do plano de fundo, adicione isso.Agora execute o aplicativo!
Delegates
estão em toda parte e você provavelmente as usa sem aviso prévio; se você criou umatableview
delegação no passado, usou muitas classes deUIKIT
trabalhos ao seu redor e muitas outrasframeworks
também, elas resolvem esses problemas principais.Parabéns, você acabou de implementar um delegado personalizado, eu sei que você provavelmente está pensando, tantos problemas só por isso? bem, delegação é um padrão de design muito importante para entender se você deseja se tornar um
iOS
desenvolvedor e sempre lembre-se de que eles têm um relacionamento individual entre os objetos.Você pode ver o tutorial original aqui
fonte
A resposta é realmente respondida, mas eu gostaria de lhe dar uma "folha de dicas" para criar um delegado:
fonte
ViewController.h
ViewController.m
MainViewController.m
Método:
fonte
No meu ponto de vista, crie uma classe separada para esse método delegado e você pode usar onde quiser.
no meu DropDownClass.h personalizado
depois disso, o arquivo in.m cria uma matriz com objetos,
Aqui estão todos definidos para a classe delegada personalizada. Depois que você pode usar esse método delegado onde desejar. Por exemplo ...
na minha outra importação viewcontroller depois disso
crie uma ação para chamar o método delegado como este
depois dessa chamada delegar método como este
fonte
Delegar: - Criar
Envie e atribua delegado para ver se você está enviando dados
fonte
// 5. Implemente o método na classe .m - (void) didRemoveCellWithTag: (NSInteger) tag {NSLog @ ("Tag% d", tag);
}
fonte
Vamos começar com um exemplo: se comprarmos um produto on-line, ele passará por processos como remessa / entrega manipulados por equipes diferentes. seria uma sobrecarga para outras pessoas / fornecedores que desejam passar essas informações apenas para as pessoas necessárias.
Portanto, se pensarmos em termos de nosso aplicativo, um evento pode ser um pedido on-line e equipes diferentes podem ter várias visualizações.
Aqui está o código considere o ShippingView como equipe de envio e DeliveryView como equipe de entrega:
fonte