I have what can be most accurately described as a Factory, which is generating some NSOperations. Before the NSOPerations are generated, I would like to check the current network status and, if the user is on a 3G/Mobile connection, warn them that they are about to do a data-heavy operation.
I attempted to do this with a UIAlertView, but the only way I can see to get the "response" from a UIAlertView is via the event-based delegate system. I was wondering if there was any way to have it act like the "confirm" dialogue in JavaScript, where it blocks the UI and I can get an immediate value from it once it is dismissed.
Is there any standard way to do this, or some example code I could be pointed towards that accomplishes something similar?
Blocking the main thread is considered bad practice on iOS, and thus there is no synchronous API for UIAlertView.
You should implement a delegate callback for the alert that enqueues the relevant NSOperation. It may be useful to subclass UIAlertView to store the relevant data you need to enqueue the NSOperation, or better yet store a block that captures the relevant variables and then just execute that when the user confirms the dialog.
You can implement something similar to that, using blocks. The execution will continue as in all other cases, but the flow of reading your code might more resemble what you want. Here is a helper class that I made for that purpose so that I can just go:
[YUYesNoListener yesNoWithTitle:#"My Title" message:#"My Message" yesBlock:^
{
NSLog(#"YES PRESSED!");
}
noBlock:^
{
NSLog(#"NO PRESSED!");
}];
...and here is the helper class:
typedef void(^EmptyBlockType)();
#interface YUYesNoListener : NSObject <UIAlertViewDelegate>
#property (nonatomic, retain) EmptyBlockType yesBlock;
#property (nonatomic, retain) EmptyBlockType noBlock;
+ (void) yesNoWithTitle:(NSString*)title message:(NSString*)message yesBlock:(EmptyBlockType)yesBlock noBlock:(EmptyBlockType)noBlock;
#end
#implementation YUYesNoListener
#synthesize yesBlock = _yesBlock;
#synthesize noBlock = _noBlock;
- (id) initWithYesBlock:(EmptyBlockType)yesBlock noBlock:(EmptyBlockType)noBlock
{
self = [super init];
if (self)
{
self.yesBlock = [[yesBlock copy] autorelease];
self.noBlock = [[noBlock copy] autorelease];
}
return self;
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0 && self.noBlock)
self.noBlock();
else if (buttonIndex == 1 && self.yesBlock)
self.yesBlock();
[_yesBlock release];
[_noBlock release];
[alertView release];
[self release];
}
- (void) alertViewCancel:(UIAlertView *)alertView
{
if (self.noBlock)
self.noBlock();
[_yesBlock release];
[_noBlock release];
[alertView release];
[self release];
}
+ (void) yesNoWithTitle:(NSString*)title message:(NSString*)message yesBlock:(EmptyBlockType)yesBlock noBlock:(EmptyBlockType)noBlock
{
YUYesNoListener* yesNoListener = [[YUYesNoListener alloc] initWithYesBlock:yesBlock noBlock:noBlock];
[[[UIAlertView alloc] initWithTitle:title message:message delegate:yesNoListener cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil] show];
}
#end
Using the code of Ricky Helgesson, I've built a Pod component to use this solution easily in any project that uses CocoaPods.
https://github.com/nmaletm/STAlertView
The code that you should use is:
[[STAlertView alloc] initWithTitle:#"Title of the alert"
message:#"Message you want to show"
cancelButtonTitle:#"No" otherButtonTitles:#"Yes"
cancelButtonBlock:^{
// Code todo when the user cancel
...
} otherButtonBlock:^{
// Code todo when the user accept
...
}];
And add at the Podfile:
pod "STAlertView"
There are more instructions at the github page.
Related
How do you pass a variable to the UIAlertView delegate?
I have a variable that I want to use in the alert view delegate. It is only used in the function that shows the UIAlertView and the UIAlertView delegate, so i don't think it should be a property on the controller. Is there a way to attach the variable to UIAlertView and retrieve it in the delegate?
- (void) someUserCondition:(SOCode *)userCode {
if ([userCode warrentsConfirmation] > 0) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Are you sure?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK",nil];
[alert setAlertViewStyle:UIAlertViewStyleDefault];
//TODO somehow store the code variable on the alert view
[alert show];
}
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:#"OK"]){
SOCode *userCode = //TODO somehow get the code from the alert view
[self continueWithCode:code];
}
}
in .h before interface:
extern const char MyConstantKey;
#interface ViewController...
in .m import:
import <objc/runtime.h>
in .m before implementation
const char MyConstantKey;
in .m implementation
-(void)viewDidAppear:(BOOL)animated{ //or wherever
NSString *aString = #"This is a string";
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Testing" message:#"test is test" delegate:self cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[alert show];
[alert release];
objc_setAssociatedObject(alert, &MyConstantKey, aString, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
in .m alertview callback
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
NSString *associatedString = objc_getAssociatedObject(alertView, &MyConstantKey);
NSLog(#"associated string: %#", associatedString);
}
Use Associated Objects. It is described in more detail here: Your New Friends: Obj-C Associated Objects
To set the object you use use:
objc_setAssociatedObject(alert, &key, userCode, OBJC_ASSOCIATION_RETAIN);
And then to get it back:
SOCode *userCode = objc_getAssociatedObject(alertView, &key);
You also need to add static char key; so that it is in the scope of moth methods.
Update
I have wrapped this into a category on UIAlertView. You can use Cocoapods to bring it in:
pod 'HCViews/UIAlertViewHCContext', '~> 1.2'
The source is available here: https://github.com/hypercrypt/HCViews/blob/master/Categories/UIAlertView%2BHCContext.h
A lot of posts talk about the concepts behind associated objects (which is good!) but sometimes you just want to see the code. Here's a clean and quick category that you can either put in a separate file or above the interface of one of your existing .m files (you could even replace UIAlertView with NSObject and effectively add a context property to any object):
#import <objc/runtime.h>
#interface UIAlertView (Private)
#property (nonatomic, strong) id context;
#end
#implementation UIAlertView (Private)
#dynamic context;
-(void)setContext:(id)context {
objc_setAssociatedObject(self, #selector(context), context, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(id)context {
return objc_getAssociatedObject(self, #selector(context));
}
#end
And then you'll be able to do something like:
NSObject *myObject = [NSObject new];
UIAlertView *alertView = ...
alertView.context = myObject;
IMPORTANT:
And don't forget to nil the context in dealloc!!
UIAlertView is a subclass of UIView which has a tag property you can set to an integer. Unfortunately if you need something other than an integer to identify/pass info to the delegate than you will need to set some properties (or set up an array with the tag indexing into it) on the delegate itself. Advaith's way will probably work but is technically not supported by Apple.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Are you sure?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK",nil];
[alert setAlertViewStyle:UIAlertViewStyleDefault];
alert.tag = SOMEINTEGER;
[alert show];
I suspect the most straight-forward way is a property in the alert view's delegate class. An alert view doesn't have any provision for "user info" and doesn't support sub-classing, which removes the only shortcuts that come to mind.
Subclass UIAlertView, add a property called userInfo with type of your choice. Set the user info value at the time you create an instance of Subclassed UIAlertView, and retrieve it from within the delegate method. (There you will get the subclassed instance which holds the userInfo)
I'm building a login system within my app that will be called several times. So instead of copying and pasting the code into several spots, I'm of course making an NSObject class so I can call the class when needed, instead.
The login system will display a UIAlertView, and when "OK" is tapped, the system will attempt to log in. I can call the class and the UIAlertView will show, but I cannot tell which buttons are tapped. Here is my code:
//Calling the login system
Login *login = [[Login alloc] init];
Login.h:
#import <Foundation/Foundation.h>
#interface Login : NSObject <UIAlertViewDelegate> {
}
#end
Login.m:
#import "Login.h"
#implementation Login
+(void)initialize {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Login" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
[alert show];
[alert release];
NSLog(#"Testing");
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"Here");
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"OK"]) {
NSLog(#"Tapped");
}
}
#end
For now, before I put UITextFields in the view, I just want to get the app to know which button was tapped. Testing appears in the log, but neither Here nor Tapped appear. Thanks!
Your alert view should not be called by the class method +(void)initialize but by the instance -(id)init method that's why your instance doesn't get the notifications.
the class method "+(void)initialize" is called when the class first load.
the instance method "-(id)init" has its name beginning by init, and is called when you create (instantiate) your object.
-(id)init {
//alert view
self = [super init];
return self;
}
Just
switch(buttonIndex){
case 0:
NSLog(#"Tapped First Button");
break;
case 1:
break;
default:
break;
}
When you use self in a class method you're referring to the class itself, rather than an instance of the class. However, your delegate method is an instance method. You probably want the caller to create a Login instance and have the instance create the alert, plus be its delegate.
It's Simple :
Create a property for your NSObject class in your view controller class :
in h file :
#property (nonatomic , retain) LoginCheckNSObject *LoginCheckerObject;
in m file :
self.LoginCheckerObject=[[LoginCheckNSObject alloc] init];
[self.LoginCheckerObject setDelegate:self];
[self.LoginCheckerObject TrackNowLogin];
I know the ARC in iOS 5 but I'm now developing pre-iOS 5 code style, and want to solve this problem by a manual release approach.
My only goal for this is to make a very handy custom alert view with UITextField.
I have a 'BigView' view that has many functions in it. And it can possibly generate many UIAlertView for many different situation on the display with that view. So I know the way use UIAlertViewDelegate for each alert view, but kind of experimentally try want to make this as like UIButton's 'addTarget'(actually it's UIControl's method).
Briefly,
This is in the part of 'BigView' class and my 'TextAlert' instance fired by a button for email gathering .
BigView.m
- (void)emailFeedback:(id)sender
{
TextAlert *textAlert = [[TextAlert alloc] initWithTitle:#"Enter your email address"];
[textAlert setTarget:self action:#selector(textAlertInputed:)];
// [textAlert release];
}
- (void)textAlertInputed:(NSString *)text
{
NSLog(#"text alert inputed, text: %#", text);
}
and these are full my TextAlert files.
TextAlert.h
#import <Foundation/Foundation.h>
#interface TextAlert : NSObject <UIAlertViewDelegate>
{
UIAlertView *alertView;
UITextField *textField;
id target;
SEL action;
}
- (id)initWithTitle:(NSString *)title;
- (void)setTarget:(id)target action:(SEL)action;
#end
TextAlert.m
#import "TextAlert.h"
#implementation TextAlert
- (id)initWithTitle:(NSString *)title
{
if (self = [super init])
{
alertView = [[UIAlertView alloc] initWithTitle:title message:#"beneath" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
textField = [[UITextField alloc] initWithFrame:CGRectMake(12, 45, 260, 25)];
CGAffineTransform myTransform = CGAffineTransformMakeTranslation(0, 60);
[alertView setTransform:myTransform];
[textField setBackgroundColor:[UIColor whiteColor]];
[alertView addSubview:textField];
[alertView show];
}
return self;
}
- (void)dealloc
{
[alertView release]; alertView = nil;
[textField release]; textField = nil;
[super dealloc];
}
- (void)setTarget:(id)_target action:(SEL)_action
{
target = _target;
action = _action;
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[target performSelector:action withObject:textField.text];
}
#end
So my main problem is the releasing point of TextAlert instance in the 'BigView' as you can see the only comment part full codes above. Of course if I remove that comment out, I got crash for call for method of deallocated.
And I also get error make textAlert instance as autoreleased one.
For me, the only solution for this is to make the 'textAlert' object in the 'BigView' a member of 'BigView' not local object. But in that case, my initial goal for handy and lightweight approach for this is not satisfied, I think. And the 'BigView' has already many member instances so I don't want to add any more.
So any suggestions? Or It will be welcome any comment for this trying. I'm ready to hear any
reproves to my insufficient code, really.
Thanks in advance,
MK
If everything works except your release problem you should only consider implementing public "show" method and private "dismiss" method (in your custom alert view).. In show method you should call [self retain] beside other things and on dismiss (add this target to button or whatever dismisses your view) call [self relese].
This isn't directly what you asked for, but could help you anyway.
Handling multiple UIAlertViews in a single UIViewController can be painful. When I ran into this problem, I found an alternative control on github, called BlockAlertsAndActionSheets. It uses blocks instead of delegates, the appearance can be fully customized (even to the default Apple-style) and there is also an "AlertView with an UITextField". Works good for me and I didn't have to reinvent that wheel! ;-)
I'm working on an app that will display a UIAlertView upon hitting it's exit button, only if progress in the game has been made. I was wondering how you would use OCUnit to intercept the UIAlertView and interact with it, or even detect if it has been presented. The only thing I can think of is to monkeypatch [UIAlertViewDelegate willPresentAlertView], but that makes me want to cry.
Does anyone know of a better method of doing this?
Update: See my blog post How to Unit Test Your Alerts and Action Sheets
The problem with my other answer is that the -showAlertWithMessage: method itself is never exercised by unit tests. "Use manual testing to verify it once" isn't too bad for easy scenarios, but error handling often involves unusual situations that are difficult to reproduce. …Besides, I got that nagging feeling that I had stopped short, and that there might be a more thorough way. There is.
In the class under test, don't instantiate UIAlertView directly. Instead, define a method
+ (Class)alertViewClass
{
return [UIAlertView class];
}
that can be replaced using "subclass and override." (Alternatively, use dependency injection and pass this class in as an initializer argument.)
Invoke this to determine the class to instantiate to show an alert:
Class alertViewClass = [[self class] alertViewClass];
id alert = [[alertViewClass alloc] initWithTitle:...etc...
Now define a mock alert view class. Its job is to remember its initializer arguments, and post a notification, passing itself as the object:
- (void)show
{
[[NSNotificationCenter defaultCenter] postNotificationName:MockAlertViewShowNotification
object:self
userInfo:nil];
}
Your testing subclass (TestingFoo) redefines +alertViewClass to substitute the mock:
+ (Class)alertViewClass
{
return [MockAlertView class];
}
Make your test class register for the notification. The invoked method can now verify the arguments passed to the alert initializer and the number of times -show was messaged.
Additional tip: In addition to the mock alert, I defined an alert verifier class that:
Registers for the notification
Lets me set expected values
Upon notification, verifies the state against the expected values
So all my alert tests do now is create the verifier, set the expectations, and exercise the call.
The latest version of OCMock (2.2.1 the at time of this writing) has features that make this easy. Here's some sample test code that stubs UIAlertView's "alloc" class method to return a mock object instead of a real UIAlertView.
id mockAlertView = [OCMockObject mockForClass:[UIAlertView class]];
[[[mockAlertView stub] andReturn:mockAlertView] alloc];
(void)[[[mockAlertView expect] andReturn:mockAlertView]
initWithTitle:OCMOCK_ANY
message:OCMOCK_ANY
delegate:OCMOCK_ANY
cancelButtonTitle:OCMOCK_ANY
otherButtonTitles:OCMOCK_ANY, nil];
[[mockAlertView expect] show];
[myViewController doSomething];
[mockAlertView verify];
Note: Please see my other answer. I recommend it over this one.
In the actual class, define a short method to show an alert, something like:
- (void)showAlertWithMessage:(NSString message *)message
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:message
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
For your test, don't test this actual method. Instead, use "subclass and override" to define a spy that simply records its calls and arguments. Let's say the original class is named "Foo". Here's a subclass for testing purposes:
#interface TestingFoo : Foo
#property(nonatomic, assign) NSUInteger countShowAlert;
#property(nonatomic, retain) NSString *lastShowAlertMessage;
#end
#implementation TestingFoo
#synthesize countShowAlert;
#synthesize lastShowAlertMessage;
- (void)dealloc
{
[lastShowAlertMessage release];
[super dealloc];
}
- (void)showAlertWithMessage:(NSString message *)message
{
++countShowAlert;
[self setLastShowAlertMessage:message];
}
#end
Now as long as
your code calls -showAlertWithMessage: instead of showing an alert directly, and
your test code instantiates TestingFoo instead of Foo,
you can check the number of calls to show an alert, and the last message.
Since this doesn't exercise the actual code that shows an alert, use manual testing to verify it once.
You can get unit tests for alert views fairly seamlessly by exchanging the 'show' implementation of UIAlertView. For example, this interface gives you some amount of testing abilities:
#interface UIAlertView (Testing)
+ (void)skipNext;
+ (BOOL)didSkip;
#end
with this implementation
#import <objc/runtime.h>
#implementation UIAlertView (Testing)
static BOOL skip = NO;
+ (id)alloc
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method showMethod = class_getInstanceMethod(self, #selector(show));
Method show_Method = class_getInstanceMethod(self, #selector(show_));
method_exchangeImplementations(showMethod, show_Method);
});
return [super alloc];
}
+ (void)skipNext
{
skip = YES;
}
+ (BOOL)didSkip
{
return !skip;
}
- (void)show_
{
NSLog(#"UIAlertView :: would appear here (%#) [ title = %#; message = %# ]", skip ? #"predicted" : #"unexpected", [self title], [self message]);
if (skip) {
skip = NO;
return;
}
}
#end
You can write unit tests e.g. like this:
[UIAlertView skipNext];
// do something that you expect will give an alert
STAssertTrue([UIAlertView didSkip], #"Alert view did not appear as expected");
If you want to automate tapping a specific button in the alert view, you will need some more magic. The interface gets two new class methods:
#interface UIAlertView (Testing)
+ (void)skipNext;
+ (BOOL)didSkip;
+ (void)tapNext:(NSString *)buttonTitle;
+ (BOOL)didTap;
#end
which go like this
static NSString *next = nil;
+ (void)tapNext:(NSString *)buttonTitle
{
[next release];
next = [buttonTitle retain];
}
+ (BOOL)didTap
{
BOOL result = !next;
[next release];
next = nil;
return result;
}
and the show method becomes
- (void)show_
{
if (next) {
NSLog(#"UIAlertView :: simulating alert for tapping %#", next);
for (NSInteger i = 0; i < [self numberOfButtons]; i++)
if ([next isEqualToString:[self buttonTitleAtIndex:i]]) {
[next release];
next = nil;
[self alertView:self clickedButtonAtIndex:i];
return;
}
return;
}
NSLog(#"UIAlertView :: would appear here (%#) [ title = %#; message = %# ]", skip ? #"predicted" : #"unexpected", [self title], [self message]);
if (skip) {
skip = NO;
return;
}
}
This can be tested similarly, but instead of skipNext you'd say which button to tap. E.g.
[UIAlertView tapNext:#"Download"];
// do stuff that triggers an alert view with a "Download" button among others
STAssertTrue([UIAlertView didTap], #"Download was never tappable or never tapped");
I'm new to the iPhone and I would like to be able to use UIAlertView in a manner similar to the Windows MessageBox() or the MessageDlg() in Delphi.
For example, I have a method that needs to ask the user for confirmation on something, and proceed based on their response.
E.g. (pseudocode):
-(void)doSomething
{
[doStep1];
[doStep2];
var myValue = [getDefaultValue];
if (myValue = nil)
{
if [promptUser(#"No value in setting. Use the default value?")] //UIAlertView here?
{
myValue = #"defaultValue";
}
else
return; // bug out of the routine 'cause we have no value.
}
[doStep3 withValue:myValue];
}
Or, put put it another way- is there a way of using UIAlertView to ask the user a question within a routine as a way of controlling the logic flow of that routine?
There's no reason to subclass UIAlertView at all. That's what delegates are for. All you need is a class (such as your view controller) supporting the UIAlertViewDelegate protocol, and set the UIAlertView's delegate property to that class. You then implement the alertView:clickedButtonAtIndex: method in this class, and the alertViewCancel: method if you want to specifically handle cancellations differently.
You can read more about it in the UIAlertView documentation and in the UIAlertViewDelegate documentation.
I have no idea what MessageDlg() is, but you can certainly subclass UIAlertView and handle the dialog response, based on which button is pressed, e.g.:
Set up the UIAlertView subclass header:
//
// ARReachabilityAlertView.h
//
#import <UIKit/UIKit.h>
#interface ARReachabilityAlertView : UIAlertView <UIAlertViewDelegate> {
}
#end
Set up the UIAlertView subclass implementation:
//
// ARReachabilityAlertView.m
//
#import "ARReachabilityAlertView.h"
#implementation ARReachabilityAlertView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setTitle:#"Error"];
[self setMessage:#"This application won't run without a network connection. Do you want to quit?"];
[self addButtonWithTitle:#"Quit"];
[self addButtonWithTitle:#"Continue"];
[self setDelegate:self];
}
return self;
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
exit(0); // quit application if "Quit" is pressed; otherwise, do nothing
}
- (void) drawRect:(CGRect)rect {
[super drawRect:rect];
}
- (void) dealloc {
[super dealloc];
}
#end
Note the alertView:clickedButtonAtIndex: delegate method. This handles the conditionals you use to decide how the application proceeds. You can send an NSNotification from here, or call a method in the application delegate, whatever you want.
In my example, this UIAlertView is instantiated if there is no network connection, and the application is closed if the user clicks "Quit" in the alert view. Otherwise, if the user clicks "Continue" the application keeps running as usual.
Note that the implementation of the subclass requires the drawRect: method be called. I'm not sure if this is a bug or not, since I'd expect the drawRect: method to be called in the super-class; I filed a bug report with Apple on this one, but I haven't heard anything. Comment it out if you want to see what the effect will be — it's kind of interesting.
I believe you're looking to use UIAlertView as a modal alert box (in the sense that you'd like your code to stop running until the user makes a selection). There's no easy way to do this, and it's really recommended that you NOT code for the iPhone in this manner. I think Alex's explanation is a good solution.
To do this, what you can do is to run the mainloop manually. I have not managed to stop the mainloop directly, so I instead run the mainloop for 0.5 seconds and wait until the user responds.
I ran into this question while researching the problem for a C#/MonoTouch user on the iPhone. The sample below is written for MonoTouch/C# but should be trivial to translate to Objective-C
The following function shows how you could implement a modal query with the above approach:
int WaitForClick ()
{
int clicked = -1;
var x = new UIAlertView ("Title", "Message", null, "Cancel", "OK", "Perhaps");
x.Show ();
bool done = false;
x.Clicked += (sender, buttonArgs) => {
Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
clicked = buttonArgs.ButtonIndex;
};
while (clicked == -1){
NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.5));
Console.WriteLine ("Waiting for another 0.5 seconds");
}
Console.WriteLine ("The user clicked {0}", clicked);
return clicked;
}
Just a quick tip: if you want a class to be a delegate for more than one UIAlertView, just use tag property to tell who is who:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Clear all" message:#"Are you sure you want to erase everything?" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK", nil];
alert.tag = ALERT_DELETE_TAG;
[alert autorelease];
[alert show];
Delegate methods are called with UIAlertView as first argument, and you can check who's the originator there.
Thanks to #miguel.de.icaza I found my solution like below (part of the code):
#interface MyClass: NSObject <UIAlertViewDelegate>
{
int confirmed;
}
- (BOOL) removeObjectAtIndex:(NSUInteger)index;
#end
#implementation
- (BOOL) removeObjectAtIndex:(NSUInteger)index
{
// delete confirmation alert
confirmed = -1;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Delete confirmation" message:#"Are you sure to delete object" delegate:self cancelButtonTitle:#"Yes" otherButtonTitles: #"No", nil];
alert.tag = 2;
[alert show];
[alert release];
// wait for confirm (0 or 1)
while (confirmed == -1) {
// this is what you need!!!
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
}
if (confirmed) {
[myObjects removeObjectAtIndex:index];
return YES;
}
else
return NO;
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (alertView.tag) {
case 1:
// ...
break;
case 2:
if (buttonIndex == 0) // delete confirmed
confirmed = 1;
else // dismiss
confirmed = 0;
break;
default:
break;
}
}
#end