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

Todd Hoff
PLUS
Todd Hoff
Courses Plus Student 159 Points

Saving the picture doesn't return to the table view, it returns to the select picture view.

I'm on Xcode6 and ios8, so I'm not sure if that's relevant or not. At about 6 minutes in we are saving the image and then dismissing the view [self dismissViewControllerAnimated:YES completion:nil];.

In the video we go back to the table view. For me that happens but then CameraView viewWillAppear is called which takes us back to the image picker.

I'm not sure why that would be. Any idea?

There are some errors:

2014-10-08 12:14:13.902 Ribbit[5955:142164] CameraView viewDidLoad 2014-10-08 12:14:14.071 Ribbit[5955:142164] Presenting view controllers on detached view controllers is discouraged <CameraViewController: 0x7aff30e0>. 2014-10-08 12:14:14.071 Ribbit[5955:142164] CameraView viewWillAppear 2014-10-08 12:14:14.285 Ribbit[5955:142164] Warning: Attempt to present <UIImagePickerController: 0x7cba0800> on <CameraViewController: 0x7aff30e0> whose view is not in the window hierarchy! 2014-10-08 12:14:18.579 Ribbit[5955:142164] CameraView viewWillAppear

5 Answers

Todd Hoff
PLUS
Todd Hoff
Courses Plus Student 159 Points

Taking the [self presentViewController:self.imagePicker animated:NO completion:nil] code out viewDidLoad and leaving the code in viewDidAppear did fix the first error, but didn't fix the problem.

Still getting...

2014-10-08 12:26:44.278 Ribbit[6081:147706] Presenting view controllers on detached view controllers is discouraged <CameraViewController: 0x7af98620>. 2014-10-08 12:26:47.001 Ribbit[6081:147706] CameraView viewWillAppear

I solved this by adding a boolean flag to indicate whether camera is on. Initiate it to NO in viewDidLoad, and set it accordingly in dismissViewControllerAnimated and presentViewController callbacks.

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

@interface CameraViewController ()

@property (nonatomic) BOOL isCameraOn;

@end

@implementation CameraViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.isCameraOn = NO;
    if (self.imagePicker == nil) {
        self.imagePicker = [[UIImagePickerController alloc] init];
        self.imagePicker.delegate = self;
        self.imagePicker.allowsEditing = NO;

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

        self.imagePicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:self.imagePicker.sourceType];
    }
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if (!self.isCameraOn) {
        [self presentViewController:self.imagePicker animated:NO completion:^{
            self.isCameraOn = YES;
        }];
    }
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 0;
}

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

    // Configure the cell...

    return cell;
}
*/

#pragma mark - Image Picker Controller delegate

- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    [self dismissViewControllerAnimated:NO completion:^{
        self.isCameraOn = NO;
    }];
    [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) {
            UIImageWriteToSavedPhotosAlbum(self.image, nil, nil, nil);
        }
    }
    [self dismissViewControllerAnimated:YES completion:^{
        self.isCameraOn = NO;
    }];
}

@end

But this still depends on the dismissViewControllerAnimated callback in didFinishPickingMediaWithInfo being called AFTER viewWillAppear delegate is called. So maybe not such robust, but it hacks for now.

Todd Hoff
PLUS
Todd Hoff
Courses Plus Student 159 Points

I did something similar. I created an isReturningFromCamera flag so I could no when to go to the picker controller or not. Seems to work. It's set to true in didFinishPickingMediaWithInfo and then checked and flipped in viewWillAppear.

Also, I heard you can also implement the UITabBarDelegate, there's a tabBar:didSelectItem: method, so you can explicitly restrict the display of imagePickerView to only from clicks on the tabBar. Although I haven't tried that out yet.