7

I'm having a terrible time getting a UIAlertView to work within my custom NSObject class. In the research I've done it appears it should be possible but here's what I've run into.

First, here's my code:

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  NSLog(@"clickedButtonAtIndex: %d", buttonIndex);
}

-(void)testAlertView {
  UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"List Contains Items"
                    message:@"List contains items.  Remove all items & delete?"
                    delegate:self
                    cancelButtonTitle:@"No"
                    otherButtonTitles:@"Yes", nil];
  [alertView show];
}

If I set the delegate to self this code crashes as soon as I tap a button. If I set it to nil clickedButtonAtIndex is never called. I've tried with and without using the <UIAlertViewDelegate>.

I know someone will ask 'why are you doing this in NSObject instead of in your UIViewController?'. Primarily because I want to separate this code out so I can use it from multiple places in my app. But also because this is a small piece of a larger block of logic that makes sense to be on it's own.

Any ideas what I'm doing wrong?

Thanks, Rich

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
rdfrahm
  • 71
  • 2
  • This code *should* work, actually. When the delegate is set and the alert crashes, where exactly does it crash and is there a stack trace? – Michael Dautermann Dec 26 '11 at 20:19
  • 1
    Has your object been deallocated by the time you tap the button ? (Objects don't usually retain their delegates) – Frederick Cheung Dec 26 '11 at 20:26
  • This is just typical. I spent hours staring at this and researching and trying one thing after another with no success, so I decided to ask for help. Not more than an hour later I finally figured it out. It had to do with the way I was creating the custom object in the calling view controller, so it had been released by the time I tapped the button, just as Frederick suggested. Thanks for the input guys! – rdfrahm Dec 26 '11 at 21:10
  • You may answer your own question and accept it, if your solution works. – dgund Jun 16 '12 at 20:18

3 Answers3

8

I had the same problem using ARC. The root of the problem was the same. I solved it by putting my custom NSObject into a "strong" property to make sure the object exists as long as the calling object (an UIVIewCOntroller in my case) exists, so when the delegate of my alert view is called I still have my custom object around and the delegate method works fine.

lfleon
  • 81
  • 1
  • 2
1

Add the NSObject as strong property:

#import "Logout.h" // is NSObject
.
.
.
@property (nonatomic, strong) Logout *logout;

Then you will get the delegatemethods called in your NSObject.

Don´t forget to register the delegate for the UIAlertView:

@interface Logout () <UIAlertViewDelegate>

and in your method:

UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"title" 
message:@"message" delegate:self cancelButtonTitle:@"cancel" 
otherButtonTitles:@"ok", nil];            

[a show];
0

How To Present An Alert View Using UIAlertController When You Don't Have A View Controller. Detail description.

Yes, you can only use UIAlertController only in UIViewController classes. So how can we do it in NSObject classes. If you see the description link given above you will get to the answer. To summarise in a line for the above description: Create a new window above the the current window. This new window will be our viewController where we display alert. So using this viewController you can call the method [presentViewController: animated: completion:].

Answer:

dispatch_async(dispatch_get_main_queue(), ^{

                    UIWindow* window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

                    window.rootViewController = [UIViewController new];
                    window.windowLevel = UIWindowLevelAlert + 1;
                    NSString *msg=@“Your mssg";
                    UIAlertController* alertCtrl = [UIAlertController alertControllerWithTitle:@“Title" message:msg preferredStyle:UIAlertControllerStyleAlert];

                    [alertCtrl addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Yes",@"Generic confirm") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

                        // do your stuff
                        // very important to hide the window afterwards.                       
                        window.hidden = YES;

                    }]];

                    UIAlertAction *cancelAction= [UIAlertAction actionWithTitle:@"cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

                         window.hidden = YES; 

                    }];

                    [alertCtrl addAction:cancelAction];

                //http://stackoverflow.com/questions/25260290/makekeywindow-vs-makekeyandvisible

                    [window makeKeyAndVisible]; //The makeKeyAndVisible message makes a window key, and moves it to be in front of any other windows on its level
                    [window.rootViewController presentViewController:alertCtrl animated:YES completion:nil];

                });
Utsav Dusad
  • 2,139
  • 4
  • 31
  • 52