Home > DeveloperSection > Forums > delegate not triggering is a mystery in ios
Ankit Singh

Total Post:341

Points:2389
Posted on    October-13-2014 12:05 AM

 iPhone iPhone  Mobile Development 
Ratings:


 2 Reply(s)
 680  View(s)
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.



Kamlakar Singh
Kamlakar Singh

Total Post:194

Points:1396
Supported
Posted on    October-13-2014 12:11 AM

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];


Pawan Shukla

Total Post:36

Points:260
Posted on    October-13-2014 12:17 AM

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];

}


Don't want to miss updates? Please click the below button!

Follow MindStick