25

我对目标 C 很陌生,我只是想弄清楚是否可以使用块或选择器作为 UIAlertView 的 UIAlertViewDelegate 参数 - 哪个更合适?

我尝试了以下方法,但它不起作用,所以我不确定我是否走在正确的轨道上?

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Checked In" 
    message:responseString
    delegate:^(UIAlertView * alertView, NSInteger buttonIndex)
                                                    {
                                                       NSLog(@"Done!");
                                                   } 
    cancelButtonTitle:@"OK" 
    otherButtonTitles: nil];

谢谢!

4

11 回答 11

28

很好的主意。这里是。就像警报视图一样,除了添加一个在解除警报时调用的块属性。(编辑 - 自原始答案以来我已经简化了这段代码。这是我现在在项目中使用的)

//  AlertView.h
//

#import <UIKit/UIKit.h>

@interface AlertView : UIAlertView

@property (copy, nonatomic) void (^completion)(BOOL, NSInteger);

- (id)initWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles;

@end

//
//  AlertView.m

#import "AlertView.h"

@interface AlertView () <UIAlertViewDelegate>

@end

@implementation AlertView

- (id)initWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles {

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

    if (self) {
        for (NSString *buttonTitle in otherButtonTitles) {
            [self addButtonWithTitle:buttonTitle];
        }
    }
    return self;
}

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

    if (self.completion) {
        self.completion(buttonIndex==self.cancelButtonIndex, buttonIndex);
        self.completion = nil;
    }
}

@end

你可以扩展这个想法来为其他委托方法提供块,但 didDismiss 是最常见的。

像这样称呼它:

AlertView *alert = [[AlertView alloc] initWithTitle:@"Really Delete" message:@"Do you really want to delete everything?" cancelButtonTitle:@"Nevermind" otherButtonTitles:@[@"Yes"]];

alert.completion = ^(BOOL cancelled, NSInteger buttonIndex) {
    if (!cancelled) {
        [self deleteEverything];
    }
};
[alert show];
于 2012-04-10T02:52:39.517 回答
2

正如Apple文档所说,必须使用 UIAlertController 来实现这种方法

UIAlertController 对象向用户显示警告消息。此类替换用于显示警报的 UIActionSheet 和 UIAlertView 类。使用您想要的操作和样式配置警报控制器后,使用 presentViewController:animated:completion: 方法呈现它。

除了向用户显示消息之外,您还可以将操作与警报控制器相关联,以便为用户提供响应方式。对于您使用 addAction: 方法添加的每个操作,警报控制器会配置一个带有操作详细信息的按钮。当用户点击该动作时,警报控制器会执行您在创建动作对象时提供的块。 苹果文档。

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"My Alert"


       message:@"This is an alert."
                                   preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
       handler:^(UIAlertAction * action) {}];

    [alert addAction:defaultAction];
    [self presentViewController:alert animated:YES completion:nil];
于 2015-11-17T06:33:20.990 回答
1

真棒的想法。我刚刚使用类别模式完成了您的想法,没有子类,直接调用 UIAlertView。请按照以下步骤操作:

  1. .h 文件中的类别 UIAlertView

    @interface UIAlertView (AlertWithBlock)
    
       - (void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegateBlock;
       - (void)setDelegateBlock:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegateBlock;
    
       + (id)alertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString   *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles delegate:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegate;
    
    @end
    
  2. 在 .m 文件中

    @implementation UIAlertView(AlertWithBlock)
    
    static char const *delegateBlockTagKey = "delegateBlockTagKey";
    
    - (void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegateBlock
    {
        return objc_getAssociatedObject(self, delegateBlockTagKey);
    }
    
    - (void)setDelegateBlock:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegateBlock
    {
        objc_setAssociatedObject(self, delegateBlockTagKey, delegateBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    + (id)alertWithTitle:(NSString *)title message:(NSString *)message cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles delegate:(void (^)(UIAlertView *alertView, NSInteger buttonIndex))delegate
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil];
        alert.delegate = alert;
        alert.delegateBlock = [delegate copy];
    
        for (NSString *buttonTitle in otherButtonTitles)
        {
            [alert addButtonWithTitle:buttonTitle];
        }
    
        [alert show];
    
        return alert;
    }
    
    #pragma mark - Delegate
    -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
    {
        if (alertView.delegateBlock)
        {
            alertView.delegateBlock(alertView, buttonIndex);
        }
    }
    
    @end
    
  3. 像这样打电话

    [UIAlertView alertWithTitle:@"Title" message:@"This is a message" cancelButtonTitle:@"Cancel" otherButtonTitles:@[@"Yes",@"No"] delegate:^(UIAlertView *alertView, NSInteger buttonIndex) {
    NSLog(@"Click at button index %ld", buttonIndex);
    }];
    

希望它有所帮助。

于 2015-01-07T08:36:18.163 回答
1

这是对 danh 实现的更新,它是不完整的,因为不可能添加多个按钮。将 va_list 传递给函数有点棘手:-)

所以你可以这样做,以便能够将多个按钮添加到UIAlertView

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

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


    if(self){
        _completion = completion;

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

    }

    return self;
}

更新:可能有更好的方法将 va_list 传递给super. 我想提一下,对我来说va_list,他们有一些神秘的东西:-)

于 2012-08-25T16:42:19.550 回答
1

我用 Swift 写了一个简单的扩展,希望对你有帮助

import UIKit

extension UIAlertView {

    func show(completion: (alertView: UIAlertView, buttonIndex: Int) -> Void){
        self.delegate = AlertViewDelegate(completion: completion)
        self.show()
    }

    class func showInput(title: String?, message: String?, cancellable: Bool, completion: (text: String?) -> Void){

        var strOK = NSLocalizedString("OK",comment: "OK")
        var strCancel = NSLocalizedString("Cancel",comment: "Cancel")
        var alert = UIAlertView(title: title, message: message, delegate: nil, cancelButtonTitle: cancellable ? strCancel : strOK)
        alert.alertViewStyle = UIAlertViewStyle.PlainTextInput
        if(cancellable) {
            alert.addButtonWithTitle(strOK)
        }
        alert.show { (alertView, buttonIndex) -> Void in
            if(cancellable && alertView.cancelButtonIndex == buttonIndex) {
                completion(text: nil)
                return
            }
            completion(text: alertView.textFieldAtIndex(0)?.text)
        }
    }

    private class AlertViewDelegate : NSObject, UIAlertViewDelegate {
        var completion :  (alertView: UIAlertView, buttonIndex: Int) -> Void
        var retainedSelf : NSObject?
        init(completion: (UIAlertView, Int) -> Void ) {
            self.completion = completion
            super.init()

            self.retainedSelf = self
        }

        func alertView(alertView: UIAlertView, didDismissWithButtonIndex buttonIndex: Int) {
            var retain = self
            retain.retainedSelf = nil
            retain.completion(alertView: alertView, buttonIndex: buttonIndex)
        }
    }
}
于 2015-02-06T03:16:50.157 回答
1

在 github 上查看这个UIAlertView-Blocks类别。我使用它并且效果很好。

于 2012-04-10T16:53:00.063 回答
0

这是另一个有用的库来做同样的事情。http://bit.ly/ichalrtvw

代码在这里:http ://bit.ly/ichalertview

于 2014-08-25T08:53:27.790 回答
0

这是我的实现,似乎与这里的大多数答案相似:http: //stavash.wordpress.com/2013/01/31/quick-tip-uialertview-with-a-block-callback/

于 2013-02-01T15:19:31.030 回答
0

查看Github 上的 UIAlertView-Blocks 类别。我写了这个并且非常易于使用并且运行良好。

祝你好运。

于 2014-04-14T18:12:45.460 回答
0

只需使用REKit。它类似于 BlocksKit,但功能更强大。

于 2013-02-14T07:38:28.657 回答
-2

我不得不稍微编辑调用示例以停止编译器错误。只是一个小小的调整,xcode 很高兴。

UIAlertViewBlock *alert = [[UIAlertViewBlock alloc] initWithTitle:@"hi"
                                                          message:@"hi there"
                                                       completion:^(BOOL canceled,NSInteger buttonIndex) {
                                                           NSLog(@"canceled=%d", canceled);
                                                           NSLog(@"pressed=%d", buttonIndex);
                                                       }
                                               cancelButtonTitle:@"cancel"
                                                otherButtonTitles:@"ok", nil];
[alert show];
于 2012-10-31T02:41:31.603 回答