Sei como os delegados funcionam e sei como posso usá-los.
Mas como eu os crio?
Sei como os delegados funcionam e sei como posso usá-los.
Mas como eu os crio?
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 o webViewDidStartLoad:
método de seu representante , você pode criar uma classe como esta:
@interface MyClass<UIWebViewDelegate>
// ...
@end
@implementation MyClass
- (void)webViewDidStartLoad:(UIWebView *)webView {
// ...
}
@end
Em seguida, você pode criar uma instância do MyClass e atribuí-la como delegada da visualização da web:
MyClass *instanceOfMyClass = [[MyClass alloc] init];
myWebView.delegate = instanceOfMyClass;
Por UIWebView
outro lado, provavelmente possui um código semelhante a este para verificar se o delegado responde à webViewDidStartLoad:
mensagem usando respondsToSelector:
e enviá-lo, se apropriado.
if([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
}
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.)
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:
@protocol UIWebViewDelegate <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, UIWebViewDelegate
neste caso. Os implementadores delegados teriam que adotar este protocolo:
@interface MyClass <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.
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.
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:
@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
Então, no corpo, podemos verificar se nosso delegado lida com mensagens acessando nossa delegateRespondsTo
estrutura, em vez de enviar -respondsToSelector:
repetidas vezes.
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:
@interface NSObject(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 delegate
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 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.
unsigned int
tipo de BOOL
como o valor de retorno delegate respondsToSelector
é do tipo BOOL
.
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>
@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
O arquivo MyClass.m deve ficar assim
#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 seu representante em outra classe (neste caso, UIViewController chamado MyVC) MyVC.h:
#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}
MyVC.m:
myClass.delegate = self; //set its delegate to self somewhere
Implementar método delegado
- (void) myClassDelegateMethod: (MyClass *) sender {
NSLog(@"Delegates are great!");
}
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:
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.
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)
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 o respondsToSelector
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 chamar setToBlue
todos 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 nil
no seu MyClass dealloc
método.
Como boa prática recomendada pela Apple, é bom que o delegado (que é um protocolo, por definição), esteja em conformidade com o NSObject
protocolo.
@protocol MyDelegate <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 @optional
anotação da seguinte maneira:
@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
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.
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.
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
}
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!"
}
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 .
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"
@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 sua notificação em outras classes: Adicione a classe como um observador:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(otherClassUpdatedItsData:) name:@"myClassUpdatedData" object:nil];
Implemente o seletor:
- (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
}
Não se esqueça de remover sua classe como observador se
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
digamos que você tenha uma classe que você desenvolveu e deseja declarar uma propriedade delegada para poder notificá-la quando algum evento acontecer:
@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
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 no MyClass
tipo ( 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 MyClass
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 na MyClass
instância e também ajuda quando o delegado se declara MyClassDelegate
em várias MyClass
instâncias, como quando você tem várias UITableView's
instâncias no seu ViewController
e se declara como um UITableViewDelegate
para todos eles.
e dentro do seu, MyClass
você notifica o delegado com eventos declarados da seguinte maneira:
if([_delegate respondsToSelector:@selector(myClass: requiredEventHandlerWithParameter:)])
{
[_delegate myClass:self requiredEventHandlerWithParameter:(ParamType*)param];
}
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).
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:
#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
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"
@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
// teste se o método foi definido antes de chamá-lo
- (void) someMethodToCallDelegate {
if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
[self.delegate delegateMethodName:self];
}
}
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:
@protocol ServiceResponceDelegate <NSObject>
- (void) serviceDidFailWithRequestType:(NSString*)error;
- (void) serviceDidFinishedSucessfully:(NSString*)success;
@end
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.
@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
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.
@interface viewController: UIViewController <ServiceResponceDelegate>
{
ServiceClass* _service;
}
- (void) go;
@end
@implementation viewController
//
//some methods
//
- (void) go
{
_service = [[ServiceClass alloc] init];
[_service setDelegate:self];
[_service someTask];
}
É isso e, ao implementar métodos delegados nesta classe, o controle retornará assim que a operação / tarefa for concluída.
Isenção de responsabilidade: esta é a Swift
versã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!
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
e 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
//MARK: step 1 Add Protocol here.
protocol ClassBVCDelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
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 UIColor
como argumento. É uma boa prática nomear seus protocolos adicionando a palavra delegate
no final do nome da classe, neste caso ClassBVCDelegate
,.
etapa 2: procure a marca de pragma etapa 2 ClassVBC
e 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 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
em ClassBVC
e 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 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.
//MARK: step 4 conform the protocol here.
class ClassAVC: UIViewController, ClassBVCDelegate {
}
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, o Swift
idioma não suporta opcional protocols
, se você quiser, pode criar uma extensão para você protocol
ou use a palavra-chave @objc em sua protocol
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
//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 ClassBVC
e atribuindo seu delegado a si mesmo, mas o que é eu aqui? bem, o eu é o ClassAVC
que foi delegado!
passo 6: Finalmente, procure o pragma do passo 6 ClassAVC
e 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!
Delegates
estão em toda parte e você provavelmente as usa sem aviso prévio; se você criou uma tableview
delegação no passado, usou muitas classes de UIKIT
trabalhos ao seu redor e muitas outras frameworks
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
A resposta é realmente respondida, mas eu gostaria de lhe dar uma "folha de dicas" para criar um 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{
}
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
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;
depois disso, o arquivo in.m cria uma matriz com 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];
}
}
}];
}
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
- (IBAction)dropDownBtn1Action:(id)sender {
DropDownViewController *vehicleModelDropView = [[DropDownViewController alloc]init];
vehicleModelDropView.dropDownType = DDCITY;
vehicleModelDropView.delegate = self;
[self presentViewController:vehicleModelDropView animated:YES completion:nil];
}
depois dessa chamada delegar método 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;
}
}
Delegar: - Criar
@protocol addToCartDelegate <NSObject>
-(void)addToCartAction:(ItemsModel *)itemsModel isAdded:(BOOL)added;
@end
Envie e atribua delegado para ver se você está enviando dados
[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 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 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
//
}
}