mamcx
mamcx

Reputation: 16196

Truly modal UIAlertView in iPhone?

I'm need run a couple of validations that depend on the decisions of the user (for example, if approve a purchase above the spending limit), and deny the "done" action if it's fail.

However, look like is not possible have a truly modal action like with other languages (like showmessage, alert(), etc) and everything is by delegates.

But then I don't know what to do. If the user push the "done" button, the program asks "Are you sure of this?" and he says "cancel" the flow continues and the view is pushed back!

How is solved this in the cocoa world?

Upvotes: 5

Views: 6984

Answers (5)

Rob
Rob

Reputation: 438277

I agree with NilObject that you generally shouldn't fight it, and generally I don't. But I'm using the AddressBookUI framework and when I'm in the delegate method,

- (BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier

I'd really like to warn the user that they are, for example, going to leave the application when they click on an address, which fires off the map app. I've used MapKit to do my own map, but I don't have the patience to reproduce the full map application (letting the user get directions from some other address), and have resorted to just letting shouldPerformDefaultAction do it's job and fire up the map app, but I have no way of warning the user that they're leaving the app.

I really wish Apple would provide a very basic model UIAlertView rather than hacking around it. This is silly.

Upvotes: 0

user1204395
user1204395

Reputation: 568

Check out: http://code.google.com/p/modal-uialertview-uiactionsheet/

With it you can do things like:

UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete" otherButtonTitles:nil];
if ([actionSheet showModalInView:self.view] == actionSheet.destructiveButtonIndex) {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:@"Do you want to delete this file?" delegate:nil cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil];
    if ([alertView showModal]!= alertView.cancelButtonIndex) {
        // Delete the file
    }
}

Upvotes: 3

miguel.de.icaza
miguel.de.icaza

Reputation: 32694

I just ran into this question as a MonoTouch question, and while researching a solution, ran into this open question.

The short answer is that yes, this is possible. The following sample shows how this is done with MonoTouch and C# on the iPhone, but the same principle applies to Objective-C.

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.

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

Upvotes: 0

Michael Langford
Michael Langford

Reputation:

Keep the state of the application in somewhere else other than the variables in the function. For instance, in one of my apps, there is a profile string that states whether or not they've agreed to the privacy policy.

Upvotes: 0

Ecton
Ecton

Reputation: 10722

The solution is not to fight it, just break up your logic into two parts. If the user clicks cancel, do not execute the second part. If the user clicks OK/Continue, execute the second part.

The main problem caused by blocking the main thread is that the main thread is what handles events. The classic way of handling events can introduce strange event handling bugs, because you don't have one event loop, instead you have multiple event loops embedded inside of one another.

By using delegates, you can utilize one event loop (invoked via UIApplicationMain), and not have any of these event handling oddities crop up.

Upvotes: 7

Related Questions