DELEGATE NOT TRIGGERING IS A MYSTERY IN IOS

Ankit Singh

Total Post:341

Points:2389
Posted by  Ankit Singh
 1053  View(s)
Ratings:
Rate this:
I have developed this class that is basically a UIAlertView with an input field that runs on blocks. So, whatever the user does on the alertView (click cancel, ok, or fill the text), returns to a block:
HEADER

typedef void (^onClickBlock)(NSInteger buttonIndex, NSString *textoInput);

 

 

@interface AlertViewBlocoComInput : NSObject

 

- (void)mostrarAlertViewBlocoComTitulo:(NSString *)titulo

                              mensagem:(NSString *)mensagem

                     tituloBotaoCancel:(NSString *)tituloCancel

                     outrosBotoesArray:(NSArray *)titulosOutrosBotoes

                   inputComPlaceHolder:(NSString *)textoPlaceholder

                      comBlocoExecucao:(onClickBlock)bloco;

 

@end

IMPLEMENTATION

 

@interface AlertComBloco : UIAlertView

@property (nonatomic, copy) onClickBlock runOnClickBlock;

@end

 

 

@implementation AlertComBloco

@end

 

 

@interface AlertViewBlocoComInput () <UIAlertViewDelegate>

@end

 

 

@implementation AlertViewBlocoComInput

 

 

- (void)mostrarAlertViewBlocoComTitulo:(NSString *)titulo

                              mensagem:(NSString *)mensagem

                     tituloBotaoCancel:(NSString *)tituloCancel

                     outrosBotoesArray:(NSArray *)titulosOutrosBotoes

                   inputComPlaceHolder:(NSString *)textoPlaceholder

                      comBlocoExecucao:(onClickBlock)bloco

 

{

 

  AlertComBloco *alerta = [[AlertComBloco alloc] initWithTitle:titulo

                                                       message:mensagem

                                                      delegate:self

                                             cancelButtonTitle:tituloCancel

                                             otherButtonTitles:nil];

  alerta.runOnClickBlock =bloco;

 

  // adicionar os outros botões

  for (NSString *umOutroBotao in titulosOutrosBotoes) {

    [alerta addButtonWithTitle:umOutroBotao];

  }

 

 

  [alerta setAlertViewStyle:UIAlertViewStylePlainTextInput];

  UITextField *input = [alerta textFieldAtIndex:0];

  input.placeholder = textoPlaceholder;

 

  [alerta show];

 

}

 

 

 

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

{

 

  AlertComBloco *alerta = (AlertComBloco *)alertView;

  onClickBlock bloco = alerta.runOnClickBlock;

 

  UITextField *input = [alertView textFieldAtIndex:0];

 

  if (bloco) {

    bloco(buttonIndex, input.text);

  }

 

}

 

 

@end





run it, it shows the alertView with the message, placeholder, perfect. I click cancel or fill the text and press ok and the alertview:clickedButtonAtIndex: is never triggered. I am not seeing why.

  1. Kamlakar Singh

    Post:194

    Points:1396
    Re: delegate not triggering is a mystery in ios

    You haven't shown us how you're calling this but most likely your AlertViewBlocoComInput is a local variable that has fallen out of scope and is therefore deallocated before the user completes their input. You can demonstrate this by temporarily adding a dealloc method that will tell you when the object is deallocated.

    - (void)dealloc

                {

                    NSLog(@"%s", __PRETTY_FUNCTION__);

                }

    In terms of fixing this, you could make your AlertViewBlocoComInput instance a class property, so it won't be released until you manually nil it. Or you can make AlertViewBlocoComInput maintain a strong reference to itself until clickedButtonAtIndex is called.

    Or, easiest, leverage the fact that UIAlertView already retains itself, so you can retire AlertComBloco altogether, folding it into AlertViewBlocoComInput:

    typedef void (^onClickBlock)(NSInteger buttonIndex, NSString *textoInput);

     

            @interface AlertViewBlocoComInput : UIAlertView <UIAlertViewDelegate>

     

            - (instancetype)initComTitulo:(NSString *)titulo

                                 mensagem:(NSString *)mensagem

                        tituloBotaoCancel:(NSString *)tituloCancel

                        outrosBotoesArray:(NSArray *)titulosOutrosBotoes

                      inputComPlaceHolder:(NSString *)textoPlaceholder

                         comBlocoExecucao:(onClickBlock)bloco;

     

            @property (nonatomic, copy) onClickBlock runOnClickBlock;

     

            @end

     

            @implementation AlertViewBlocoComInput

     

            - (instancetype)initComTitulo:(NSString *)titulo

                                 mensagem:(NSString *)mensagem

                        tituloBotaoCancel:(NSString *)tituloCancel

                        outrosBotoesArray:(NSArray *)titulosOutrosBotoes

                      inputComPlaceHolder:(NSString *)textoPlaceholder

                         comBlocoExecucao:(onClickBlock)bloco

     

            {

                self = [super initWithTitle:titulo message:mensagem delegate:self cancelButtonTitle:tituloCancel otherButtonTitles:nil];

     

                if (self) {

                    self.runOnClickBlock =bloco;

     

                    // adicionar os outros botões

                    for (NSString *umOutroBotao in titulosOutrosBotoes) {

                        [self addButtonWithTitle:umOutroBotao];

                    }

     

                    [self setAlertViewStyle:UIAlertViewStylePlainTextInput];

                    UITextField *input = [self textFieldAtIndex:0];

                    input.placeholder = textoPlaceholder;

                }

     

                return self;

            }

     

            - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

            {

                if (self.runOnClickBlock) {

                    UITextField *input = [alertView textFieldAtIndex:0];

                    self.runOnClickBlock(buttonIndex, input.text);

                }

            }

     

            @end

    And you'd call it like so:

    AlertViewBlocoComInput *obj = [[AlertViewBlocoComInput alloc] initComTitulo:@"title" mensagem:@"message" tituloBotaoCancel:@"OK" outrosBotoesArray:nil inputComPlaceHolder:@"Placeholder" comBlocoExecucao:^(NSInteger buttonIndex, NSString *textoInput) {

        // do whatever you want with `buttonIndex` and `textoInput` here

        //

        // NSLog(@"%ld %@", (long)buttonIndex, textoInput);

    }];

    [obj show];

  1. Pawan Shukla

    Post:38

    Points:274
    Re: delegate not triggering is a mystery in ios

    You can directly subclass UIAlertView and add your own initializer. I have abstracted your classes to a single subclass of UIAlertView and it works fine. Please see my posts below,


    typedef void (^onClickBlock)(NSInteger buttonIndex, NSString *textoInput);

     

            @interface AlertComBloco : UIAlertView<UIAlertViewDelegate>

            @property (nonatomic, copy) onClickBlock runOnClickBlock;

            @end

     

     

            @implementation AlertComBloco

     

     

            - (id)initWithTitulo:(NSString *)titulo mensagem:(NSString*)mensagem tituloBotaoCancel:(NSString*)tituloCancel outrosBotoesArray:(NSArray *)titulosOutrosBotoes inputComPlaceHolder:(NSString *)textoPlaceholder

                comBlocoExecucao:(onClickBlock)bloco{

              if(self = [self initWithTitle:titulo message:mensagem delegate:self cancelButtonTitle:tituloCancel otherButtonTitles:nil, nil]){

                _runOnClickBlock = bloco;

                for (NSString *umOutroBotao in titulosOutrosBotoes) {

                  [self addButtonWithTitle:umOutroBotao];

                }

                [self setAlertViewStyle:UIAlertViewStylePlainTextInput];

                UITextField *input = [self textFieldAtIndex:0];

                input.placeholder = textoPlaceholder;

     

              }

              return self;

            }

     

     

     

            - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

            {

     

              UITextField *input = [alertView textFieldAtIndex:0];

     

              if (self.runOnClickBlock) {

                self.runOnClickBlock(buttonIndex, input.text);

              }

     

            }

     

            @end

    Then, you could call it with the block in your view controller just like this,

            - (void)showAlert:(id)sender{

      AlertComBloco *alertCombo = [[AlertComBloco alloc] initWithTitulo:@"Hi" mensagem:@"Custom Alert" tituloBotaoCancel:@"Cancel" outrosBotoesArray:@[@"Other"] inputComPlaceHolder:@"Placeholder" comBlocoExecucao:^(NSInteger buttonIndex, NSString *textoInput) {

        NSLog(@"Button at index %ld, with text %@", (long)buttonIndex, textoInput);

      }];

      [alertCombo show];

    }

Answer

NEWSLETTER

Enter your email address here always to be updated. We promise not to spam!