ios - tutorial - Como faço para criar delegados em Objective-C?




swift firebase auth (13)

Versão rápida

Um delegado é apenas uma classe que faz algum trabalho para outra classe. Leia o código a seguir para um exemplo de Playground um pouco bobo (mas esperançosamente esclarecedor) que mostre 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 real, os delegados são freqüentemente usados ​​nas seguintes situações

  1. Quando uma classe precisa comunicar alguma informação para outra classe
  2. Quando uma classe quer permitir que outra classe a personalize

As classes não precisam saber nada uma da outra antes, exceto que a classe delegada está em conformidade com o protocolo necessário.

Eu recomendo ler os dois artigos seguintes. Eles me ajudaram a entender os delegados ainda melhor do que a documentation .

Eu sei como os delegados trabalham e sei como posso usá-los.

Mas como eu os crio?


A resposta aprovada é ótima, mas se você estiver procurando por uma resposta de 1 minuto, tente isto:

O arquivo MyClass.h deve ficar assim (adicionar linhas delegadas 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

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 delegado em outra classe (UIViewController chamado MyVC neste caso) MyVC.h:

#import "MyClass.h"
@interface MyVC:UIViewController <MyClassDelegate> { //make it a delegate for MyClassDelegate
}

MyVC.m:

myClass.delegate = self;          //set its delegate to self somewhere

Implementar o método delegado

- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}

Aqui está um método simples para criar delegados

Crie o protocolo no arquivo. Certifique-se de que é definido antes do protocolo usando @class seguido pelo nome do UIViewController < As the protocol I am going to use is UIViewController class>.

Passo 1: Crie um novo protocolo de classe chamado "YourViewController", que será a subclasse da classe UIViewController e atribua esta classe ao segundo ViewController.

Passo 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.

Passo: 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

// testa se o método foi definido antes de você chamá-lo

 - (void) someMethodToCallDelegate {
     if ([[self delegate] respondsToSelector:@selector(defineDelegateMethodName:)]) {
           [self.delegate delegateMethodName:self]; 
     }
  }

Como uma boa prática recomendada pela Apple, é bom que o delegado (que é um protocolo, por definição) esteja em conformidade com o protocolo NSObject .

@protocol MyDelegate <NSObject>
    ...
@end

& para criar métodos opcionais dentro de seu delegado (isto é, métodos que não necessariamente precisam ser implementados), você pode usar a anotação @optional assim:

@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, você precisa (em sua classe) verificar com respondsToSelector se a exibição (que está em conformidade com seu delegado) implementou realmente o (s) método (s) opcional (is).


Eu acho que todas essas respostas fazem muito sentido quando você entende os delegados. Pessoalmente eu vim da terra de C / C + + e antes que as linguagens procedurais como Fortran etc então aqui é meu 2 min assumir encontrar análogos semelhantes no paradigma C + +.

Se eu fosse explicar delegados a um programador C ++ / Java, eu diria

O que são delegados? Estes são ponteiros estáticos para classes dentro de outra classe. Depois de atribuir um ponteiro, você pode chamar funções / métodos nessa classe. Daí algumas funções da sua classe são "delegadas" (em C ++ mundo - ponteiro para por um ponteiro de objeto de classe) para outra classe.

O que são protocolos? Conceitualmente, serve como propósito similar 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 um delegado dentro de uma classe.

Como posso fazer algo semelhante em C ++? Se você tentou fazer isso em C ++, você definiria ponteiros para classes (objetos) na definição de classe e, em seguida, conectando-os a outras classes que fornecerão funções adicionais como delegados para 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 assume que os programadores não são os melhores em manter essa deciplina e fornece restrições de compilador para impor uma implementação limpa.


Ok, isso não é realmente uma resposta para a pergunta, mas se você está procurando como fazer o seu próprio delegado, talvez algo muito mais simples possa ser uma resposta melhor para você.

Eu dificilmente implemento meus delegados porque eu raramente preciso. Eu posso ter apenas um delegado para um objeto delegado. Portanto, se você deseja que seu delegado tenha dados de comunicação / transmissão de uma forma, é muito melhor do que com as notificações.

NSNotification pode passar objetos para mais de um destinatário e é muito fácil de usar. Funciona assim:

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 turma como observador se

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Por favor! confira abaixo um simples tutorial passo a passo para entender como os delegados trabalham no iOS.

Delegar no iOS

Eu criei dois ViewControllers (para enviar dados de um para outro)

  1. FirstViewController implementa delegado (que fornece dados).
  2. SecondViewController declara o delegado (que receberá dados).

Talvez isso seja mais do tipo que você está perdendo:

Se você está vindo de um ponto de vista semelhante ao C ++, os delegados demoram um pouco para se acostumar - mas basicamente "eles simplesmente funcionam".

A maneira como isso funciona é que você define algum objeto que escreveu como o representante para NSWindow, mas seu objeto tem implementações (métodos) apenas para um ou alguns dos muitos métodos de delegação possíveis. Então algo acontece, e o NSWindow quer chamar seu objeto - ele apenas usa o método respondsToSelector do Objective-c para determinar se o seu objeto quer aquele método chamado, e então o chama. É assim que o objective-c funciona - os métodos são procurados sob demanda.

É totalmente trivial fazer isso com seus próprios objetos, não há nada especial acontecendo, você poderia, por exemplo, ter um NSArray de 27 objetos, todos os tipos diferentes de objetos, apenas 18 alguns deles tendo o método -(void)setToBue; Os outros 9 não. Então, para chamar setToBlue em todos os 18 que precisam ser feitos, 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, então você sempre tem que definir o delegado como nil no seu método MyClass dealloc .


A resposta está 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

Delegado: - Criar

@protocol addToCartDelegate <NSObject>

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

@end

Envie e por favor atribua delegado para ver se você está enviando dados

[self.delegate addToCartAction:itemsModel isAdded:YES];

Um delegado Objective-C é um objeto que foi atribuído à propriedade delegate outro objeto. Para criar um, você simplesmente define uma classe que implementa os métodos delegados nos quais está interessado e marca essa classe como implementando o protocolo delegado.

Por exemplo, suponha que você tenha um UIWebView . Se você quiser implementar o método webViewDidStartLoad: seu delegado, poderá criar uma classe como esta:

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

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

Em seguida, você poderia criar uma instância do MyClass e atribuí-la como o representante da visualização da Web:

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

No lado do UIWebView , provavelmente tem um código semelhante a este para ver se o delegado responde à mensagem webViewDidStartLoad: usando respondsToSelector: e a envia, se apropriado.

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

A propriedade delegada em si é geralmente declarada weak (no ARC) ou assign (pré-ARC) para evitar reter loops, já que o delegado de um objeto geralmente mantém uma referência forte a esse objeto. (Por exemplo, um controlador de exibição geralmente é o delegado de uma exibição que ele contém.)

Fazendo Delegados para Suas Classes

Para definir seus próprios representantes, você terá que declarar seus métodos em algum lugar, conforme discutido no documento da Apple sobre protocolos . Você geralmente declara um protocolo formal. A declaração, parafraseada de 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 seu delegado, UIWebViewDelegate nesse caso. Implementadores delegados teriam que adotar este protocolo:

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

Em seguida, implemente os métodos no protocolo. Para métodos declarados no protocolo como @optional (como a maioria dos métodos delegados), você precisa verificar com -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 usam o objeto de delegação como o primeiro parâmetro. Eles também costumam usar um testamento, deve ou não. Portanto, webViewDidStartLoad: (primeiro parâmetro é a visualização da Web) em vez de loadStarted (sem parâmetros) por exemplo.

Otimizações de velocidade

Em vez de verificar se um delegado responde a um seletor toda vez que quisermos enviá-lo, você pode armazenar essas informações em cache quando os delegados estiverem definidos. Uma maneira muito limpa de fazer isso é usar um campo de bit, 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

Em seguida, no corpo, podemos verificar se nosso delegado manipula mensagens acessando nossa estrutura delegateRespondsTo , em vez de enviar -respondsToSelector: repetidamente.

Delegados Informais

Antes dos protocolos existirem, era comum usar uma category no NSObject para declarar os métodos que um delegado poderia implementar. Por exemplo, o CALayer ainda faz isso:

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

Isso essencialmente diz ao compilador que qualquer objeto pode implementar displayLayer:

Em seguida, você usaria a mesma abordagem -respondsToSelector: descrita acima para chamar esse método. Os delegados simplesmente implementam esse método e atribuem a propriedade delegate , e é isso (não há declaração de 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, pois essa abordagem polui o NSObject (o que torna o autocomplete menos útil) e dificulta que o compilador o avise sobre erros de digitação e erros semelhantes.


Vamos começar com um exemplo, se comprarmos um produto on-line, ele passa por processo como envio / entrega manipulado por diferentes equipes. Portanto, se o envio for concluído, a equipe de envio deve notificar a equipe de entrega e deve ser uma comunicação de um para transmitir essa informação seria sobrecarga para outras pessoas / fornecedor pode querer passar essa informação apenas para pessoas necessárias.

Então, se pensarmos em termos de nosso aplicativo, um evento pode ser um pedido on-line e equipes diferentes podem ser como várias visualizações.

Aqui está o código que considera ShippingView como equipe de entrega 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
        //
    }
}

//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);

}





delegates