How to access user input from UIAlertView completi

2019-04-15 06:33发布

问题:

Using iOS6:

I would like to retrieve the text entered by a user into a UITextField associated with the UIAlertView. I am aware that I could achieve the desired result with a delegate however I am curious about solving this issue with a callback function as I believe this may be an interesting pattern. I began by examining a common pattern for category extension of the UIAlertView class. Code below. Thanks in advance for any suggestions.

import <UIKit/UIKit.h>

@interface UIAlertView (Block)
- (id)initWithTitle:(NSString *)title message:(NSString *)message completion:(void (^)(BOOL cancelled,     NSInteger buttonIndex, UITextField *textField))completion cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION;

@end

The .m for the category follows:

#import "UIAlertView+Block.h"
#import <objc/runtime.h>


static char const * const alertCompletionBlockTag = "alertCompletionBlock";

@implementation UIAlertView (Block)

- (id)initWithTitle:(NSString *)title
            message:(NSString *)message
         completion:(void (^)(BOOL cancelled, NSInteger buttonIndex))completion
  cancelButtonTitle:(NSString *)cancelButtonTitle
  otherButtonTitles:(NSString *)otherButtonTitles, ... {

self = [self initWithTitle:title message:message delegate:self cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil ];


if (self) {
    objc_setAssociatedObject(self, alertCompletionBlockTag, completion, OBJC_ASSOCIATION_COPY);

    va_list _arguments;
    va_start(_arguments, otherButtonTitles);

    for (NSString *key = otherButtonTitles; key != nil; key = (__bridge NSString *)va_arg(_arguments, void *)) {
        [self addButtonWithTitle:key];
    }
    va_end(_arguments);
}

[self setAlertViewStyle:UIAlertViewStylePlainTextInput];
return self;
}


- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {

id completion = objc_getAssociatedObject(self, alertCompletionBlockTag);

[self complete:completion index:buttonIndex];
}

- (void) complete:(void (^)(BOOL cancelled, NSInteger buttonIndex))block index:(NSInteger)buttonIndex {
BOOL _cancelled = (buttonIndex == self.cancelButtonIndex);
block(_cancelled, buttonIndex );

objc_setAssociatedObject(self, alertCompletionBlockTag, nil, OBJC_ASSOCIATION_COPY);
//objc_removeAssociatedObjects(block);
}


@end

Usage for the category is set below. The main problem is my inability to reference the UIAlertView textField at Index 0 from within the completion block.

[[[UIAlertView alloc] initWithTitle:@"Add"
                           message:@"Add New Asset Type"
                        completion:^(BOOL cancelled, NSInteger buttonIndex){
                            if (!cancelled) {

                                //call on completion of UISheetAction ???
                                NSLog(@"%@",needToAccessUIAlertView._textFields[0]);



                            }
                        }
                 cancelButtonTitle:@"Cancel"
                 otherButtonTitles:@"OK", nil] show];

回答1:

So basically you want to access the alert view from the block. You can do something like this:

__block __weak UIAlertView *alertViewWeak;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Add"
                           message:@"Add New Asset Type"
                        completion:^(BOOL cancelled, NSInteger buttonIndex){
                            if (!cancelled) {

                                //call on completion of UISheetAction ???
                                NSLog(@"%@",[alertViewWeak textFieldAtIndex:0]);



                            }
                        }
                 cancelButtonTitle:@"Cancel"
                 otherButtonTitles:@"OK", nil];
alertViewWeak = alertView;
[alertView show];


回答2:

If you want to make a category by yourself, above is good enough. But, there are many classes that uses delegation pattern. Do you want to make categories one by one?

There is REKit. With it, you can use that classes as if they were Block-based:

UIAlertView *alertView;
alertView = [[UIAlertView alloc]
    initWithTitle:@"title"
    message:@"message"
    delegate:nil
    cancelButtonTitle:@"Cancel"
    otherButtonTitles:@"OK", nil
];
[alertView
    respondsToSelector:@selector(alertView:didDismissWithButtonIndex:)
    withKey:nil
    usingBlock:^(id receiver, UIAlertView *alertView, NSInteger buttonIndex) {
        // Do something…
    }
];
alertView.delegate = alertView;


回答3:

Try this library Here is another useful library to do the same. http://ichathan.com/2014/08/19/ichalertview/