有没有简单的方法来处理 UIAlertView 结果而无需委托?

Posted

技术标签:

【中文标题】有没有简单的方法来处理 UIAlertView 结果而无需委托?【英文标题】:is there easy way to handle UIAlertView result without delegation? 【发布时间】:2012-03-12 04:49:51 【问题描述】:

我有一个函数显示一个带有是/否按钮的 UIAlertView,它只在函数的范围内使用,所以我不想实现一个委托来捕捉用户反馈。

有没有办法知道用户点击了哪些按钮而不实现 UIAlertViewDelegate,例如:

[alert show];
if([alert indexOfClickedButton] == indexOfYes)

....

或动画中的 lambda 表达式

【问题讨论】:

没有委托的 UIALertview 只有一种方法可以创建自定义 UIALertview。 这是一个实现基于块的 UIAlertview(以及其他东西)的站点:blog.mugunthkumar.com/coding/… UIAlertView *aletView = [[UIAlertView alloc] initWithTitle:@"Any Title" message:@"Hiii" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil]; [警报显示];如果你愿意,不要使用任何委托。 【参考方案1】:

没有办法完全避免委托,但您可以按照以下思路创建一个包装器:

@interface MyAlertViewDelegate : NSObject<UIAlertViewDelegate>

typedef void (^AlertViewCompletionBlock)(NSInteger buttonIndex);
@property (strong,nonatomic) AlertViewCompletionBlock callback;

+ (void)showAlertView:(UIAlertView *)alertView withCallback:(AlertViewCompletionBlock)callback;

@end


@implementation MyAlertViewDelegate
@synthesize callback;

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


+ (void)showAlertView:(UIAlertView *)alertView
         withCallback:(AlertViewCompletionBlock)callback 
    __block MyAlertViewDelegate *delegate = [[MyAlertViewDelegate alloc] init];
    alertView.delegate = delegate;
    delegate.callback = ^(NSInteger buttonIndex) 
        callback(buttonIndex);
        alertView.delegate = nil;
        delegate = nil;
    ;
    [alertView show];


@end

(假定为 ARC,如果您不使用它,请将 delegate = nil 更改为 [delegate release]。)

用法类似于:

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Confirm" message:@"Yes or No?" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:@"Yes",@"No", nil];
[MyAlertViewDelegate showAlertView:alert withCallback:^(NSInteger buttonIndex) 
    // code to take action depending on the value of buttonIndex
];

【讨论】:

我在您执行delegate = nil 的行上收到编译器警告:在此块中强烈捕获委托可能会导致保留周期。这在 ios 5.1 ARC 下。 delegate = nil 是必要的,因为alertView.delegate 是非保留属性,我们需要保留对象“委托”,直到警报视图按钮回调完成。警告(误报)可以在之前使用#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-retain-cycles",在该行之后使用#pragma clang diagnostic pop 来忽略。 太好了,谢谢!您可以在创建警报时传递delegate:nil 2015 年更新:UIAlertView 已弃用,其替代品 UIAlertController 允许使用 UIAlertAction 添加操作,它将块作为操作处理程序。【参考方案2】:

我写了一篇关于如何(以及为什么)将块回调添加到警报视图、操作表和动画的博客文章:

http://blog.innovattic.com/uikitblocks/

如果您只是想要一个有效的实现,您可以从 GitHub 下载源文件:

https://github.com/Innovattic/UIKit-Blocks

用法:

UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"My easy alert"  
                                                message:@"Would you like to perform some kind of action?"
                                      cancelButtonTitle:@"No"
                                      otherButtonTitles:@"Yes", nil];
[alert setHandler:^(UIAlertView* alert, NSInteger buttonIndex) 
    NSLog(@"Perform some kind of action");
 forButtonAtIndex:[alert firstOtherButtonIndex]];
[alert show];

【讨论】:

【参考方案3】:

这很容易。假设您有一个警报,如下所示:

//Alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Confirm" message:@"Yes or No?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Yes",@"No", nil];
[alert show];

你需要添加这个方法:

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

此方法的可能实现如下所示:

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

//Checks For Approval
    if (buttonIndex == 1) 
        //do something because they selected button one, yes
     else 
        //do nothing because they selected no
    

【讨论】:

但他特意问了如何无需授权... 谢谢!是的,它会为我节省一些代码行,但我仍然需要在函数范围之外编写一些代码,并且可能保存 alertview 的引用,这是我不想要的。我正在寻找基于块的解决方案,如果没有简单的方法可以做到这一点,我认为您的解决方案将是最好的。 很高兴我能帮上忙! @jAckOdE 如果您不想保留警报视图对象的引用,您可以使用标签作为警报视图。例如,警报 = 101;在 - (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 中,您可以检查,如果 alert.tag == 101 ....【参考方案4】:

您可以使用自定义视图来执行此操作,该视图可以隐藏和显示以避免 ActionSheets

UIView *AlertVw=[UIView alloc]initWithFrame:CGRect(x,y,w,h)]];

UIButton *SaveButton=[UIButton alloc]initWithFrame:CGRect(x,y,w,h)]];
[CustomButton setTitle:@"Ok" forState:UIControlStateNormal];
[SaveButton addTarget:self action:@selector(SaveClicked)            forControlEvents:UIControlEventTouchUpInside];

UIButton *CancelButton=[UIButton alloc]initWithFrame:CGRect(x,y,w,h)]];
[CustomButton setTitle:@"Cancel" forState:UIControlStateNormal];
[CancelButton addTarget:self action:@selector(CancelClicked)            forControlEvents:UIControlEventTouchUpInside];

[AlertVw addSubview:SaveButton];
[AlertVw addSubview:CancelButton];

[self.view addSubview:AlertVw];

-(void)SaveButton
 
   //Code to apply on Save clicked
  [AlertVw removeFromSuperView];  //Also you can use AlertView.hidden=YES;

 
-(void)CancelButton
 
   //Code to apply on cancel clicked
  [AlertVw removeFromSuperView];  //Also you can use AlertView.hidden=YES;

 

【讨论】:

【参考方案5】:

无需派生类。使用 Block,很容易获得用户选择的按钮索引。

typedef void(^AlertViewCallBackBlock)(NSInteger selectedIndex);

@interface ABC ()
    @property (nonatomic, copy) AlertViewCallBackBlock alertViewBlock;
@end

@implementation

- (void)showAlert 
    self.alertViewBlock = ^(NSInteger selectedIndex) 
        if (selectedIndex == 1) 

        
    ;
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Confirm" message:@"Yes or No?" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Yes",@"No", nil];
    [alert show];


- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex 
    self.alertViewBlock(buttonIndex);

@end

【讨论】:

【参考方案6】:

谢谢Arkku。这是 Swift 版本。

https://github.com/exchangegroup/alert-view-with-callback-swift

let alertView = UIAlertView(...)

AlertViewWithCallback().show(alertView)  alertView, buttonIndex in
  println("You closed alert by tapping button #\(buttonIndex)")

【讨论】:

【参考方案7】:

UIAlertView 已从 iOS 8.0 中弃用,更好的解决方案是使用 UIAlertController

let alert = UIAlertController(title: "message", message: "Title", preferredStyle: .Alert)

alert.addAction(UIAlertAction(title: "YES", style: .Default, handler:  (action) -> Void in
    // Action for YES
))
alert.addAction(UIAlertAction(title: "NO", style: .Default, handler:  (action) -> Void in
    // Action for NO
))

self.view.window!.rootViewController!.presentViewController(alert, animated: true, completion: nil)

【讨论】:

以上是关于有没有简单的方法来处理 UIAlertView 结果而无需委托?的主要内容,如果未能解决你的问题,请参考以下文章

UIAlertView 没有禁用所有交互

UIAlertView 处理文本字段

UIALertView的基本用法与UIAlertViewDelegate对对话框的事件处理方法

我想在 UIAlertView 上显示 UIProgressView

在 UIAlertView 中使用滑块?

是否可以使用标签访问 UIAlertView?