Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

viewDidAppear UIActionSheet Appears Twice

Hello, I'm using viewDidLoad to have a UIActionsheet to appear when loading the a view but it appears twice after using actionsheet. here is some of the code.

  • (void) viewDidAppear:(BOOL)animated {

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Take a Picture",@"Choose from Library", nil];

    [actionSheet showInView:self.view];

}

I tried using this [actionSheet dismissWithClickedButtonIndex:0 animated:YES];

but the actionsheet just disappears quickly and you are unable to use it. I assume that I'm dismissing it incorrectly but I can't seem to find any solutions.

Any advice and help ? Thank you! and Happy Holidays!

9 Answers

I've added 2 lines in your viewDidLoad in your editView (though you should probably have named it editViewController instead).

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated]; // Added this for sanity sake

     // check directly into the UIImageView since you saved your image there in the imagepicker delegate
    if (self.photoView.image == nil) {
// this is the same as what you have
        UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Take a Picture",@"Choose from Library", nil];
        [actionSheet showInView:self.view];
    }
}

Also since you are instantiating your image picker from - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex You can safely delete the method - (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex

You have it in View did appear. If it was In view did load It would only appear once, But in view did appear it will appear each time The view appears.

Well you see I'm using a push segue to another view and then the camera opens automatically but it says I can't use viewDidLoad unless the ViewController is a UIWindow but since I'm using a navigation controller I am also unable to go back to my first view and the camera doesn't load.

can you explain exactly what you are trying to accomplish in detail? ie user taps button in view controller x which pushes view controller y on top of that, then the camera is presented modally, after that blah blah blah. ). I think I could probably help you out more if I knew what you wanted to do.

You are correct to show your UIActionSheet in viewDidAppear: You just have to flag those two lines so it doesn't get called if a picture has already been selected, e.g.

if (self.selectedPicture == nil) {
  UIActionSheet...
}

On the sheet getting dismissed too quickly, if you are trying to perform a specific action such as performing a segue after the action sheet is dismissed through selecting a specific button, you should implement the delegate methods either actionSheet:willDismissWithButtonIndex: or actionSheet:didDismissWithButtonIndex: These delegate methods are called when any button is pressed, which always cause the actionSheet to be dismissed.

For example:

- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex
{
  if (buttonIndex == 0) {
     // Present UI for taking a picture
  } else if (buttonIndex == 1) {
     // Present UI for selecting a picture
  }
}

Calling [actionSheet dismissWithClickedButtonIndex:0 animated:YES]; directly means you are simulating a button click action on the button at index 0. Hence the actionSheet is, as you witnessed, dismissed prematurely. A usage of this is a timeout action, for instance, if you wait for 10 seconds and don't receive a response from a user, you can call this method to trigger a default action such as cancel:

...
[actionSheet showInView:self.view];

int64_t delayInSeconds = 10.;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// check that it is still visible
    if (actionSheet.isVisible) {
        [actionSheet dismissWithClickedButtonIndex:actionSheet.cancelButtonIndex animated:YES];
    }
});

So using

if (self.selectedPicture == nil) {

UIActionSheet...

}

will allow the actionsheet to only appear once unless a photo was taken or selected? also where would I put this? ive been trying to use some of your examples but I guess I'm using them incorrectly... kinda a objective C newbie. But thank you for commenting with some help I greatly appreciate it!

(Edited)

That is assuming you saved your picture in a property named selectedPicture, you might have named the image (selected or taken via camera). Here's what your viewDidLoad will look like with just the action sheet code:

- (void)viewDidAppear:(BOOL)animated
{
   [super viewDidAppear:animated];
   if (self.selectedImage == nil) {
       // if the selectedImage has not been set, i.e. not selected, we present
       // the action sheet
       UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Take a Picture",@"Choose from Library", nil];
       [actionSheet showInView:self.view];

        // Don't worry about time out dismiss unless that's a behavior you wish to implement
   }
}

Then, since you've set the delegate of actionSheet to self already in your initWithTitle:..., you would implement the delegate method within the same class, perhaps at the end before @end. You can throw in NSLog's in the if statements and watch them as they are called to help you understand what's going on, e.g.

- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex
{
  if (buttonIndex == 0) {
     // Present UI for taking a picture
     NSLog(@"Button at index 0 is pressed. Take a picture!");
  } else if (buttonIndex == 1) {
     // Present UI for selecting a picture
     NSLog(@"Button at index 1 is pressed. Look into the photo library.");
  }
}

For some reason my actionsheet isn't appear...? maybe i misunderstood you.

If you can zip it up and upload it somewhere I can take a look for you.

Here you go! please forgive me for any of this code isn't properly used. Still in the learning process :)

Oh my goodness! thank you so much! my app is finally coming together. You've been so helpful thank you very much!