How to push a modal view from didFinishPickingMediaWithInfo - iphone

I've got an imagePickerController which allows the user to take or select an image.
In - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info; I would like to trigger opening another modal view to capture the caption. I have a call for that purpose...
-(void) getcaption:(id) obj {
textInput * ti = [[textInput alloc] initWithContent:#"" header:#"Caption for photo" source:2];
ti.delegate = self;
[self presentModalViewController:ti animated:YES];
[ti release];
}
The question is how to call getcaption without triggering a spiral of
#6663 0x324abb18 in -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] ()
At the moment I do
[self performSelector:#selector(getcaption:) withObject:nil afterDelay:(NSTimeInterval)1];
in didFinishPickingMediaWithInfo
which is nasty, and only 95% reliable

I assume the problem is that you are attempting to show your new view before your old view has closed? I assume you are in a parent view controller that is displaying both modal views with it being the parent. If that is the case, the point at which you should display the new modal view is when the parent view has completely finished hiding the previous modal view. Specifically, this happens at
- (void) viewDidAppear:(BOOL)animated
You'll want to make sure that you only show the second modal view after the previous one has finished, of course (that is, don't show it when the parent view is appearing for any other reason)

Related

dismissModalViewAnimated actually removes parent view

I have an application that allows a user to add a picture to a log.
If the user chooses to add from library, everything is fine, but if a user chooses to take
a picture with the camera there's an issue:
When the camera modal view is animated in and I either take a picture and tap on "Use" or i click on the "Cancel" button, the view I'm in when calling dismissModalViewAnimated is removed from its superview.
Anyone got an explanation for this?
Here's the code I use for presenting the modal viewcontroller
pickerCont = [[UIImagePickerController alloc] init];
pickerCont.delegate = self;
pickerCont.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:pickerCont animated:YES];
And this is what i use to dismiss it:
[self dismissModalViewControllerAnimated:YES]
Actually you are dissmissing parentview. here self represents parentView
Use UIImagePickerController's delegate to dissmiss UIImagePickerController
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//get picked image here
[pickerCont dismissModalViewControllerAnimated:YES]
}

what's called after returning from presentModalViewController / dismissModalViewControllerAnimated:

to show a modal uiview out of my mainView I use:
[self presentModalViewController:myController animated:YES];
and in MyController I close that view with:
[self dismissModalViewControllerAnimated:YES];
But how can I know in the mainView that the modal was finished (to redraw my table)?
Currently I set a local variable to YES in my mainView after starting the modal view an react on viewWillAppear:
[self presentModalViewController:myController animated:YES];
_reloadTableData = YES;
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (_reloadTableData) {
_reloadTableData = NO;
[_tableView reloadData];
}
}
Is there a better way to do so ?
Generally speaking, it's not appropriate to dismiss the modal view by the modal view itself.
Instead, you should set your main view as the delegate of the modal view. When you modal view finishes its task, it can let its delegate know and let its delegate dismiss it. This is the very common so-called delegate design pattern in Objective-C.
btw, you may want to consult with some code samples to gain a better understanding of this delegate pattern. I suggest you take a look at one of Xcode's default templates - the Utility Application template. It has a very succinct and simple and straightforward delegate structure built inside.

ImagePicker in view hierarchy problem

I can't figure out the most effective and "elegant" method for doing some task. The problem definition is:
I want to display several views, one of them is the ImagePicker with camera roll source.
The hierarchy looks similar to this:
MAIN VIEW ---> PICKER ---> IMAGE PROCESSING VIEW
When the user tap "back button" UI has to allow backward displaying.
I have tried several options:
1.
a) MAIN VIEW presents picker view modally.
b) In didFinishPickingMediaWithInfo delegate method dismiss picker modal view and after that invoke presentModalViewController with IMAGE PROCESSING VIEW.
Sample code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage* pickedImage = [info valueForKey:UIImagePickerControllerEditedImage];
LastViewController* vc = [[LastViewController alloc] init];
vc.mainImage = pickedImage;
[self dismissModalViewControllerAnimated:NO];
[self presentModalViewController:vc animated:NO];
}
Problem is that, it doesn't works, cause controller can't display next modal after dismissing another (previouse won't disappear immediately, MAIN isn't active immediately, and can't present the new one).
2.
MAIN VIEW presents IMAGE PROCESSING VIEW modally, but immediately after that IMAGE PROCESSING VIEW is presenting picker view modally, waiting for done, dismissing picker and user can see IMAGE PROCESSING VIEW with image from library.
Sample code:
in some action of main view controller:
ImageProcessViewController *vc = [[ImageProcessViewController alloc] initWithNibName:#"ImageProcessViewController" bundle:nil];
vc.delegate = self;
vc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:vc animated:NO];
[vc release];
in ImageProcessViewController:
- (void)viewDidLoad {
[super viewDidLoad];
//some UI init here
if(self.sourceType == UIImagePickerControllerSourceTypePhotoLibrary) {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentModalViewController:ipc animated:NO];
[ipc release];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage* pickedImage = [info valueForKey:UIImagePickerControllerEditedImage];
self.mainImage = pickedImage;
[self dismissModalViewControllerAnimated:NO];
}
Problem is that, i can't call presentModalViewController in viewDidLoad method because it won't work (it is too early in view controller live cycle I guess). I tried also in viewDidAppear, but in that case I have to set some ivar flag, to display picker view only once and empty IMAGE PROCESSING VIEW is displayed for short time before image picker view and i don't want this.
3.
I tried to figure out how to use Navigation Controller to do this, beacause UIImagePickerController is using his nav controller, but this is private structure and documentation says programmers can't do that.
Please give me some suggestions because I really lost my way at the moment
In your main view controller, use viewDidAppear:animated: - this will be called when the modal transition has finished. You can safely start another modal transition from there.

How to switch views when Iphone camera returns?

I am new to Iphone development. I am working on an application which involves two views. I have a camera button in view one which opens up the default Iphone camera. This is achieved by having this code in the IBAction for camera button in ViewOneController:
UIImagePickerController *picker =
[[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:picker animated:YES];
[picker release];
The view controller for the first view is also the UIImagePickerControllerDelegate for the camera. When the picture is clicked and the camera view returns to the function imagePickerController:didFinishPickingWithMediaInfo where I do this:
(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissModalViewControllerAnimated:YES];
[self presentModalViewController:ViewTwoViewController animated:YES];
}
So basically all I am trying to achieve is from viewone click "take picture" ---> Open camera --> after camera is done jump to view two. Quite simmilar to what it is in the flickr app. However after I take the picture from camera my app returns to view one and view two is not shown. What am I missing here?
Also from a conceptual perspective I guess IOS keeps a stack of views for any app. When presentModalViewController is called the view is shown and it is added to the stack and when dismissModalViewController is called the view is removed from the stack and the parent view is show. Is that right?
Thanks.
You probably need to put the call to [self presentModalViewController:ViewTwoViewController animated:YES] in viewWillAppear which will be called after the picker view has been removed.
You probably also need to surround the call with some check to only present viewTwo when applicable.

after dismissing modal view, parent view seems deallocated?

I'm writing an iPhone app. Starting from a view controller in a navigation stack [called EditCreatorController], I am presenting a custom modal view controller [called BMSStringPickerController]. I have created a delegate protocol, etc. per the Apple guidelines for passing data back to the first view and using that view to dismiss the modal view. I even get the expected data back from the modal controller and am able to dismiss it just fine. The problem is, at that point, almost any action I take on the original view controller leads to debugger errors like
-[EditCreatorController performSelector:withObject:withObject:]: message sent to deallocated instance 0x3a647f0
or
-[EditCreatorController tableView:willSelectRowAtIndexPath:]: message sent to deallocated instance 0x3c12c40
In other words, it seems like the original view controller has evaporated while the modal view was showing. This is true no matter which of the two delegate callbacks is invoked.
Here is the code from the parent controller that invokes the modal view:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 1) { // selection on creator type row
// create a string picker to choose new creator type from list
BMSStringPickerController *picker = [[BMSStringPickerController alloc] initWithNibName:#"BMSStringPickerController" bundle:nil];
picker.delegate = self;
picker.stringChoices = [NSArray arrayWithObjects:#"composer", #"lyricist", #"arranger", #"original artist", #"other", nil];
picker.currentChoice = creator.type;
picker.title = #"Creator Type";
// wrap it in a nav controller so we can get tile bar etc. (from VC prog guide p. 93)
UINavigationController *newNavigationController = [[UINavigationController alloc]
initWithRootViewController:picker];
[self.navigationController presentModalViewController:newNavigationController animated:YES];
[newNavigationController release];
[picker release];
}
}
And here are the delegate callbacks:
- (void)stringPickerController:(BMSStringPickerController *)picker didPickString:(NSString *)string {
NSLog(#"received string back: %#", string);
typeLabel.text = string; // only change the label for now; object only changes if done button pressed
[self.tableView reloadData];
[self dismissModalViewControllerAnimated:YES];
}
- (void)stringPickerControllerDidCancel:(BMSStringPickerController *)picker {
NSLog(#"picker cancelled");
[self dismissModalViewControllerAnimated:YES];
}
Another weird thing (perhaps a clue) is that although I get the "received string back" NSLog message, and assign it to typeLabel.text (typeLabel is an IBOutlet to a label in my table view), it never appears there, even with the table reload.
Anyone have some ideas?
Maybe you release the delegate in dealloc of BMSStringPickerController?
It may not solve your problem, but I suggest telling the picker to dismiss itself (in the delegate methods), allowing the responder chain to correctly handle the dismiss:
[picker dismissModalViewControllerAnimated:YES];
The default behavior when there is a memory warning is the release the view of all view controllers that are not visible. So if there was a memory warning while in your modal view controller, its parent view controller could have its view unloaded.
When this happens, viewDidUnload is called on the view controller so that you can release any references you hold into the view. If you have references that you didn't retain they will become invalid when the view is unloaded. Maybe this is happening in your case?
See the UIViewController reference Memory Management section for details. The UIViewController method didReceiveMemoryWarning: releases the view if the view is not currently visible and then calls viewDidUnload.