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 Build a Self-Destructing Message iPhone App Capturing Photo and Video Using UIImagePickerController Saving the Media

Sara Strickler
Sara Strickler
3,221 Points

UIImagePickerController is not being dismissed properly...

Hi there!

I'm having trouble with the CameraViewController - I'm able to load the camera, and take and save pictures. Once I've selected "Use Photo", I expect to be taken to the table view of my friends - I can see it for a split second, but then the modal UIImagePickerController pops back up again immediately.

I've also noticed that when I'm in the inbox and I select the "Camera" tab, I can see the table view of my friends for a split second.

Not sure if this is related, (or what it means) but when I take a photo and select "Use Photo" I'm seeing this in the console - Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates.

Here's my project - https://www.dropbox.com/sh/dgh95i8lntv5qoz/AADmixUXfw6ZE_yaZ6YBa0Ifa?dl=0

3 Answers

Amit Bijlani
STAFF
Amit Bijlani
Treehouse Guest Teacher

In your viewWillAppear method you are missing a critical if statement which prevents the UIImagePickerController from appearing again and again. Remember the viewWillAppear method is called each time the view controller is about to appear. So when you dismiss the image picker controller and your CameraViewController appears, it presents the UIImagePickerController once again since you have no checks in place. This is what it should look like:

    if (self.image == nil && [self.videoFilePath length] == 0) {

        self.imagePicker = [[UIImagePickerController alloc] init];
        self.imagePicker.delegate = self;
        self.imagePicker.allowsEditing = NO;
        self.imagePicker.videoMaximumDuration = 10;

        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
            self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
        }
        else
        {
            self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        }
        self.imagePicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:self.imagePicker.sourceType];

        [self presentViewController:self.imagePicker animated:NO completion:nil];
    }

For future reference I'd highly recommend comparing the project files from the course against your own code to see what you have done differently.

The project files seem to be at a later stage of the project than where this video leaves off. The code above works great but it isn't actually implemented yet at this point of the lesson, and yet the code works in the video and the does not on my machine. Wondering why that is.

I'm having the same problem Alex.

Stanley Gao
Stanley Gao
3,889 Points

I have the exact same problem with xcode 6. In fact, adding this if statement only partially fix the problem. Plus, how did Ben's project runs just fine without the if statement? I realized that every time I click the "camera" on the tab bar, the table view of recipients will flash in a split of second before the camera actually pop out. There is definitely something wrong with viewWillAppear methods.

Ugo Besa
Ugo Besa
6,209 Points

I think I have another solution:

  • (void) viewWillAppear:(BOOL)animated{

    [super viewWillAppear:animated];

    if(!animated){

    // self.imagePicker ...

Alex Danson
Alex Danson
8,737 Points

I also had this issue which I managed to solve upon reviewing the video.

In the final section of the video, he dismisses the 'UIViewControllerImagePicker' after completing the saving of the video. He CUTS the 'dismissViewControllerAnimated' method from the 'if' statement which follows the saving of an image and pastes it after all of the 'if' 'else' statements, so that it will always be called.

I had copied the 'dismissViewControllerAnimated' method instead of cutting it which resulted in the same issue that you're having i.e. That the 'UIViewControlerImagePicker' kept reappearing instead of reverting to my list of friends. Having now deleted the first instance of the 'dismissViewControllerAnimated' method, my code works fine so I wonder if your issue could be solved in the same way?

Here is my whole didFinishPickingMediaWithInfo method:

- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
        self.image = [info objectForKey:UIImagePickerControllerOriginalImage];
        if (self.imagePicker.sourceType == UIImagePickerControllerSourceTypeCamera) {
            UIImageWriteToSavedPhotosAlbum(self.image, nil, nil, nil);
        }
    }
    else {

        NSURL *imagePickerURL = [info objectForKey:UIImagePickerControllerMediaURL];
        self.videoFilePath = [imagePickerURL path];
        if (self.imagePicker.sourceType == UIImagePickerControllerSourceTypeCamera) {
            if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(self.videoFilePath)) {
                UISaveVideoAtPathToSavedPhotosAlbum(self.videoFilePath, nil, nil, nil);
            }
        }

    }
    [self dismissViewControllerAnimated:YES completion:nil];
}
The Starlord
The Starlord
886 Points

Im still having the same issue.. cameral roll or video keeps looping after taking picture or a video instead of showing cameratableviewcontroller, dismissViewControllerAnimated is placed just before closing the delegate method but still fails to dismiss the modal view controller

I'm using xcode 6 with 8.3 SDK.

//
//  CameraTableViewController.m
//  Ribbit
//
//  Created by Syed Ehteshamuddin on 2015-04-16.
//  Copyright (c) 2015 techbate.com. All rights reserved.
//

#import "CameraTableViewController.h"
#import <MobileCoreServices/UTCoreTypes.h>

@interface CameraTableViewController ()

@end

@implementation CameraTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
//    self.imagePicker = [[UIImagePickerController alloc]init];
//    self.imagePicker.delegate = self;
//    self.imagePicker.allowsEditing = NO;
//    self.imagePicker.videoMaximumDuration = 10;
//    
//    self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
//    self.imagePicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:self.imagePicker.sourceType ];
//    [self presentViewController:self.imagePicker animated:nil completion:nil];

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    self.imagePicker = [[UIImagePickerController alloc]init];
    self.imagePicker.delegate = self;
    self.imagePicker.allowsEditing = NO;
    self.imagePicker.videoMaximumDuration = 10;

    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
        self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    }else{
        self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    }
    self.imagePicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:self.imagePicker.sourceType ];
    [self presentViewController:self.imagePicker animated:nil completion:nil];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
#warning Potentially incomplete method implementation.
    // Return the number of sections.
    return 0;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
#warning Incomplete method implementation.
    // Return the number of rows in the section.
    return 0;
}

/*
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<#@"reuseIdentifier"#> forIndexPath:indexPath];

    // Configure the cell...

    return cell;
}
*/

/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return NO if you do not want the specified item to be editable.
    return YES;
}
*/

/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    } else if (editingStyle == UITableViewCellEditingStyleInsert) {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }   
}
*/

/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/

/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return NO if you do not want the item to be re-orderable.
    return YES;
}
*/

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

#pragma mark - image picker controller delegate
-(void) imagePickerControllerDidCancel:(UIImagePickerController *)picker{
    [self dismissViewControllerAnimated:NO completion:nil];
    [self.tabBarController setSelectedIndex:0];
}

-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

    NSString * mediaType = [info objectForKey:UIImagePickerControllerMediaType];
    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
        self.image = [info objectForKey:UIImagePickerControllerOriginalImage];
        if(self.imagePicker.sourceType== UIImagePickerControllerSourceTypeCamera){
            //save the image
            UIImageWriteToSavedPhotosAlbum(self.image, nil, nil, nil);
                    }
        }else{
        self.videoFilePath = (NSString *)([[info objectForKey:UIImagePickerControllerMediaURL]path]);
        if(self.imagePicker.sourceType== UIImagePickerControllerSourceTypeCamera){
            //save the video
            if(UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(self.videoFilePath)){
            UISaveVideoAtPathToSavedPhotosAlbum(self.videoFilePath, nil, nil, nil);
            }

    }


}
    [self dismissViewControllerAnimated:YES completion:nil];

}

@end