is there easy way to handle UIAlertView result without delegation? - iphone

I have a function that shows a UIAlertView with YES/NO buttons, and it is used only inside the function's scope so I dont want to implement a delegation to catch the user feedback.
Is there any way to know what button users clicked without implement UIAlertViewDelegate, something like:
[alert show];
if([alert indexOfClickedButton] == indexOfYes)
{
....
}
Or lambda expression as in Animation

There is no way to avoid delegation completely, but you could create a wrapper to that effect along these lines:
#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 is assumed, if you are not using it change delegate = nil to [delegate release].)
Usage would be something like:
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
}];

I have written a blog post about how to (and why) add block callbacks to alert views, action sheets and animations:
http://blog.innovattic.com/uikitblocks/
If you just want a working implementation of this you can download the sources files from GitHub:
https://github.com/Innovattic/UIKit-Blocks
Usage:
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];

It's very easy. Say you have an alert, something like this:
//Alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Confirm" message:#"Yes or No?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Yes",#"No", nil];
[alert show];
You're going to need to add this method:
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
A possible implementation of this method would look like this:
- (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
}
}

You can do this using custom view which can be hidden and shown to avoid 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;
}

No need to derive the class. With Block, it is easy to get user selected button index.
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

Thanks Arkku. Here is the Swift version.
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)")
}

UIAlertView is deprecated from iOS 8.0, a better solution will be using 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)

Related

Can not dismiss an action sheet here

A UILongPressGestureRecognizer is added to my imageView with action handleLongPressOnPhotos. The most related codes is as following:
- (IBAction)handleLongPressOnPhotos:(UILongPressGestureRecognizer *)sender
{
self.imageWillBeSaved = (UIImageView *)sender.view; //breakPoint1
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Save the photo" otherButtonTitles: #"Go to the Original photo", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView:self.view]; //breakPoint2
NSLog( #"actionSheet addr when created is %p", actionSheet );//breakPoint3
[actionSheet release];//breakPoint4
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
case 0:
UIImageWriteToSavedPhotosAlbum(self.imageWillBeSaved.image, self, #selector(image: didFinishSavingWithError:contextInfo:), nil);
//[actionSheet dismissWithClickedButtonIndex:0 animated:YES]; i have tried to use this method here, but it didn't work.
break;
default:
break;
}
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if (error != NULL)
{
// handle error
}
else
{
// handle ok status
}
}
The action sheet will not be dismissed after i click the "save the photo" button. If i click the button again, the action sheet dismissed and the photo saved twice.Any problem in the code? Thanks in advance!
Ps. the imageView is a subview of a scrollView, and the scrollView is in a tableViewCell.
- (IBAction)handleLongPressOnPhotos:(UILongPressGestureRecognizer *)sender
{
self.imageWillBeSaved = (UIImageView *)sender.view; //breakPoint1
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Save the photo" otherButtonTitles: #"Go to the Original photo", nil];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView:self.view]; //breakPoint2
NSLog( #"actionSheet addr when created is %p", actionSheet );//breakPoint3
[actionSheet release];//breakPoint4
}
I set two breakpoint in the "handleLongPressOnPhotos:" method as breakPoint1 and breakPoint1. I followed the steps of the code after the imageView was longPressed. The step order is :breakPoint1 -> breakPoint2 ->breakPoint1 ->breakPoint2 - > breakPoint3 -> breakPoint4 - > breakPoint3 -> breakPoint4, then went out. It is obvious that the actionSheet has been presented twice, that cause the problem. It is odd, and I do not know the reason and avoid this.
Problem solved in another question UILongPressGestureRecognizer gets called twice when pressing down
thanks to #Laddu, #MichaelDautermann, #sreecharan
IT Looks OK but please add nslog here:-
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
NSLog(#"buttonIndex.....%d",buttonIndex);
switch (buttonIndex) {
case 0:
UIImageWriteToSavedPhotosAlbum(self.imageWillBeSaved.image, self, #selector(image: didFinishSavingWithError:contextInfo:), nil);
//[actionSheet dismissWithClickedButtonIndex:0 animated:YES]; i have tried to use this method here, but it didn't work.
break;
default:
break;
}
}
Check you add ACtionSheet Delegate in .h file also .
is there a reason why you are not using actionSheet:willDismissWithButtonIndex: instead of actionSheet:clickedButtonAtIndex:.
If you use actionSheet:willDismissWithButtonIndex:, you don't need to care about dismissing the ActionSheet yourself.
Problem solved in another question UILongPressGestureRecognizer gets called twice when pressing down
thanks to #Laddu, #MichaelDautermann, #sreecharan

Block for UIAlertViewDelegate

I'm pretty new to objective C and I'm just trying to figure out if I can use a block or a selector as the UIAlertViewDelegate argument for UIAlertView - and which is more appropriate?
I've tried the following but it just isn't working so I'm not sure if I'm on the right track or not?
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Checked In"
message:responseString
delegate:^(UIAlertView * alertView, NSInteger buttonIndex)
{
NSLog(#"Done!");
}
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
Thanks!
Great idea. Here it is. Just like alert view, except adds a block property that's invoked when the alert is dismissed. (Edit - I've simplified this code since the original answer. Here's what I use now in projects)
// 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
You can extend this idea to supply blocks for other delegate methods, but the didDismiss is the most common.
Call it like this:
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];
One must use UIAlertController for that approach as Apple document says
A UIAlertController object displays an alert message to the user. This
class replaces the UIActionSheet and UIAlertView classes for
displaying alerts. After configuring the alert controller with the
actions and style you want, present it using the
presentViewController:animated:completion: method.
In addition to displaying a message to a user, you can associate
actions with your alert controller to give the user a way to respond.
For each action you add using the addAction: method, the alert
controller configures a button with the action details. When the user
taps that action, the alert controller executes the block you provided
when creating the action object.
Apple Docs.
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];
Check out this UIAlertView-Blocks category on github. I use this and it works well.
This is an update to danh's implementation, which is incomplete because it is not possible to add multiple buttons. Passing a va_list to a function is a little tricky :-)
So you could do this, in order to be able to add multiple buttons to the 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;
}
Update: There might be a better way of passing the va_list to super. I would like to mention that to me va_lists have something mystic to them :-)
Awesome idea. I have just completed exactly your idea using Category pattern, no subclass, call directly UIAlertView. Please follow these steps:
Category UIAlertView in .h file
#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
In .m file
#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
Call like this
[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);
}];
Hope it help.
I have written a simple extension in Swift, hope it helpful
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)
}
}
}
Here is my implementation, seems like it's similar to most answers here:
http://stavash.wordpress.com/2013/01/31/quick-tip-uialertview-with-a-block-callback/
Simply use REKit. It's similar to BlocksKit, but it's more powerful.
Check out UIAlertView-Blocks category on Github.
I wrote this and is very easy to use and works well.
Good luck.
Here is another useful library to do the same. http://bit.ly/ichalrtvw
Code here: http://bit.ly/ichalertview
I had to edit the calling example a bit to stop complier error. Just a small tweak and xcode was happy.
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];

Multiple UIActionSheets on the same delegate

I'm writing a puzzle game. When the user presses the check button, I see if the solution they entered is correct. Depending on the result, I present one of two action sheets for them. For now I just have some NSLog statements to make sure things are getting called, but only one of the sheets seems to work properly.
Nothing gets called when I click a button in showErrorsActionSheet. The action sheet disappears off the screen, but the logs never print.
I suspect it has something to do with having two actionsheets declared to the same delegate (self)
- (void) checkSolution {
//code determines the value of the BOOL allCorrect
if (allCorrect) { //IF ALL OF THE LETTERS WERE CORRECT
//display UIAlertView;
NSLog(#"allCorrect");
UIActionSheet *levelCompleteActionSheet = [[UIActionSheet alloc] initWithTitle:#"Congratulations! You Have Finished the Level!" delegate:self cancelButtonTitle:#"Review my work" destructiveButtonTitle:#"Choose next puzzle" otherButtonTitles:nil, nil];
[levelCompleteActionSheet showInView:self.view];
[levelCompleteActionSheet release];
}
else {
//[self showIncorrectLettersInRed];
UIActionSheet *showErrorsActionSheet = [[UIActionSheet alloc] initWithTitle:#"Sorry, thats not right. Show errors in red?" delegate:self cancelButtonTitle:#"No Thanks, I'll keep trying" destructiveButtonTitle:#"Yes please, I'm stuck!" otherButtonTitles:nil, nil];
[showErrorsActionSheet showInView:self.view];
[showErrorsActionSheet release];
}
}
the methods that are supposed to be called are:
- (void) levelCompleteActionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (buttonIndex != [actionSheet cancelButtonIndex]) {
NSLog(#"return to levelSelect");
//pushViewController:levelSelect
}
else {
NSLog(#"continue to examine solution");
}
}
- (void) showErrorsActionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (buttonIndex != [actionSheet cancelButtonIndex]) {
NSLog(#"show errors in red");
}
else {
NSLog(#"continue to try");
}
}
and Ive declared the UIActionSheet protocol in the interface file as follows:
#interface GamePlay : UIViewController <UIActionSheetDelegate> {
Set a tag for each actionSheet, then use a switch statement in the UIActionSheet delegate.
Assign a tag
- (void)checkSolution
{
if (allCorrect)
{
UIActionSheet *levelCompleteActionSheet = [[UIActionSheet alloc] initWithTitle:#"Congratulations! You Have Finished the Level!" delegate:self cancelButtonTitle:#"Review my work" destructiveButtonTitle:#"Choose next puzzle" otherButtonTitles:nil, nil];
[levelCompleteActionSheet setTag: 0];
[levelCompleteActionSheet showInView:self.view];
[levelCompleteActionSheet release];
}
else
{
UIActionSheet *showErrorsActionSheet = [[UIActionSheet alloc] initWithTitle:#"Sorry, thats not right. Show errors in red?" delegate:self cancelButtonTitle:#"No Thanks, I'll keep trying" destructiveButtonTitle:#"Yes please, I'm stuck!" otherButtonTitles:nil, nil];
[showErrorsActionSheet setTag: 1];
[showErrorsActionSheet showInView:self.view];
[showErrorsActionSheet release];
}
}
UIActionSheet Delegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch ( actionSheet.tag )
{
case 0: /* levelCompleteActionSheet */
{
switch ( buttonIndex )
{
case 0: /* 1st button*/
break;
case 1: /* 2nd button */
break;
}
}
break;
case 1: /* showErrorsActionSheet */
break;
}
}
The same would apply anywhere else in this class as well, including levelCompleteActionSheet: and showErrorsActionSheet:. The only difference is, you would need to create an iVar for each actionSheet instead of creating them in checkSolution.
The methods that will be called by a UIActionSheet on its delegate are the methods listed in the UIActionSheetDelegate protocol.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIModalViewDelegate_Protocol/UIActionSheetDelegate/UIActionSheetDelegate.html
To be called, your method must be one of those methods. I don't see levelCompleteActionSheet or showErrorsActionSheet listed in that protocol! :) Your method must be named actionSheet:clickedButtonAtIndex:, and not some name you make up out of whole cloth.
Using Tag solve this problem
levelCompleteActionSheet.tag = 100;
showErrorsActionSheet.tag = 101;
- (void) levelCompleteActionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
if(actionSheet.tag == 100){
// levelCompleteActionSheet implement your required function
}
else if(actionSheet.tag == 101){
// showErrorsActionSheet implement your required function
}
}

Make UIAlertView Button trigger function On Press

Currently I am using the following code to present a UIAlertView:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Today's Entry Complete"
message:#"Press OK to submit your data!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
[alert release];
How do I get it so that when 'OK" is pressed, it triggers a function, say -(void)submitData
NOTE:
Important: UIAlertView is deprecated in iOS 8. (Note that UIAlertViewDelegate is also deprecated.) To create and manage alerts in iOS 8 and later, instead use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert.
Please check this out tutorial
"deprecated" means???
Objectvie C
.h file
#interface urViewController : UIViewController <UIAlertViewDelegate> {
.m file
// Create Alert and set the delegate to listen events
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Today's Entry Complete"
message:#"Press OK to submit your data!"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"OK", nil];
// Set the tag to alert unique among the other alerts.
// So that you can find out later, which alert we are handling
alert.tag = 100;
[alert show];
//[alert release];
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
// Is this my Alert View?
if (alertView.tag == 100) {
//Yes
// You need to compare 'buttonIndex' & 0 to other value(1,2,3) if u have more buttons.
// Then u can check which button was pressed.
if (buttonIndex == 0) {// 1st Other Button
[self submitData];
}
else if (buttonIndex == 1) {// 2nd Other Button
}
}
else {
//No
// Other Alert View
}
}
Swift
The Swifty way is to use the new UIAlertController and closures:
// Create the alert controller
let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .Alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alertController.addAction(okAction)
alertController.addAction(cancelAction)
// Present the controller
self.presentViewController(alertController, animated: true, completion: nil)
If you are using multiple UIAlertView instances that are not declared in the class's interface you can also set a tag to identify instances in your delegate method, for example:
somewhere on top of your class file myClass.m
#define myAlertViewsTag 0
creating the UIAlertView:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"My Alert"
message:#"please press ok or cancel"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"OK", nil];
alert.tag = myAlertViewsTag;
[alert show];
[alert release];
the delegate method:
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (alertView.tag == myAlertViewsTag) {
if (buttonIndex == 0) {
// Do something when cancel pressed
} else {
// Do something for ok
}
} else {
// Do something with responses from other alertViews
}
}
You need to set the delegate when allocating the alertview, then use one of the UIAlertViewDelegate methods to call your own method, for example:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Today's Entry Complete"
message:#"Press OK to submit your data!"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
[self submitData];
}
You need to setup the delegate for your UIAlertView, before showing it. Then do the work in the delegate callback as such:
-(void)alertView:(UIAlertView*)alert didDismissWithButtonIndex:(NSInteger)buttonIndex;
{
if ([[alert buttonTitleAtIndex] isEqualToString:#"Do it"]) {
// Code to execute on Do it button selection.
}
}
My CWUIKit project over at https://github.com/Jayway/CWUIKit has an addition to UIAlertView that allow you to do the same thing but with blocks. Redusing the same operation for both creating, showing and handling the alert to this:
[[UIAlertView alertViewWithTitle:#"My Title"
message:#"The Message"
cancelButtonTitle:#"Cancel"
otherTitlesAndAuxiliaryActions:#"Do it",
^(CWAuxiliaryAction*a) {
// Code to execute on Do it button selection.
}, nil] show];
If you want to use blocks you can also use MKAdditions to achieve this easily even for multiple UIAlertViews.
Just use a code similar to this sample:
[[UIAlertView alertViewWithTitle:#"Test"
message:#"Hello World"
cancelButtonTitle:#"Dismiss"
otherButtonTitles:[NSArray arrayWithObjects:#"First", #"Second", nil]
onDismiss:^(int buttonIndex)
{
NSLog(#"%d", buttonIndex);
}
onCancel:^()
{
NSLog(#"Cancelled");
}
] show];
You can find more information in this tutorial: http://blog.mugunthkumar.com/coding/ios-code-block-based-uialertview-and-uiactionsheet
Little more clarification,
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//handles title you've added for cancelButtonTitle
if(buttonIndex == [alertView cancelButtonIndex]) {
//do stuff
}else{
//handles titles you've added for otherButtonTitles
if(buttonIndex == 1) {
// do something else
}
else if(buttonIndex == 2) {
// do different thing
}
}
}
Example,
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Need your action!"
message:#"Choose an option to continue!" delegate:self cancelButtonTitle:#"Not Need!"
otherButtonTitles:#"Do Something", #"Do Different", nil];
[alert show];
(it's iOS7 screenshot)
From iOS8 Apple provide new UIAlertController class which you can use instead of UIAlertView which is now deprecated, its is also stated in depreciation message
UIAlertView is deprecated. Use UIAlertController with a preferredStyle
of UIAlertControllerStyleAlert instead
So you should use something like this
Objective C
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:#"Title"
message:#"Message"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* yesButton = [UIAlertAction
actionWithTitle:#"Yes, please"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//Handle your yes please button action here
}];
UIAlertAction* noButton = [UIAlertAction
actionWithTitle:#"No, thanks"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//Handle no, thanks button
}];
[alert addAction:yesButton];
[alert addAction:noButton];
[self presentViewController:alert animated:YES completion:nil];
Swift
The Swifty way is to use the new UIAlertController and closures:
// Create the alert controller
let alertController = UIAlertController(title: "Title", message: "Message", preferredStyle: .Alert)
// Create the actions
let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) {
UIAlertAction in
NSLog("OK Pressed")
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) {
UIAlertAction in
NSLog("Cancel Pressed")
}
// Add the actions
alertController.addAction(okAction)
alertController.addAction(cancelAction)
// Present the controller
self.presentViewController(alertController, animated: true, completion: nil)

UIAlertView button tagging

Is there a way I can add a .tag to an UIAlertView button? Reason being, I'm adding a few dynamic buttons to the alert that will sometimes be in the alert and sometimes not. I figured the best way was to add a tag. Is there a better method for this?
The options that will ALWAYS be in the alert are Email, Save. And the 2 optional options are Tweet This and Facebook.
Thanks for any help in advance!
There is one method buttonTitleAtIndex for UIAlertView. Use that to find the button tapped by user.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *buttonString = [alertView buttonTitleAtIndex:buttonIndex];
if( [buttonString isEqualToString:#"Facebook"] ){
// your code here
} else if( [buttonString isEqualToString:#"twitter"] ){
// your code here
}
}
You can also use tag proprerty:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Info"
message:#"Info text"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil, nil];
[alert setTag:0];
Then in delegate:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
switch (alertView.tag) {
case 1: {
...
break;
}
...
default:
break;
}