UIViewControllers tripping over each other - iphone

Need some best practice advice here...
Navigation based application. Root view is a UITableView where user can drill down to a detail UIViewController (call it VC1). User wants to initiate some task but it may require additional info before it can proceed. If so then VC1 allocs & presents modal VC2 using the "flip" transition holding a strong reference to VC2 in a property.
All fairly standard. Here's where I'm running into trouble. Once user fills out required info in VC2 the app can either continue on to a MFMailComposeViewController or flip back to VC1. If they continue to MailCompose then when that dismisses it should return to VC1.
VC2 has a weak reference to VC1 and the problem arrises when VC2 tries to dismiss itself and present MFMailComposeViewController:
[self dismissModalViewControllerAnimated:YES];
[VC1 performSelector:#selector(showMailModalView) withObject:nil afterDelay:0.2];
I get a EXC_BAD_ACCESS on VC1 because, apparently, my weak reference to VC1 has already been dealloc'd even though VC1 has strong reference to VC2!?!
So my question is...how should this be handled? Would the delegate pattern be better? How would that be triggered?
Note: VC1 is quite large and VC2 isn't often needed so I'm trying to keep VC2 as separate as possible from VC1 (including its own NIB).

VC2 has a weak reference to VC1 and the problem arrises when VC2 tries
to dismiss itself and present
MFMailComposeViewController:
What you have is a circular dependency, since VC1 knows about VC2 and then you let VC2 know about VC1. And When you have circular dependencies, you get all sorts of problems.
You should be using the delegate pattern here. When VC1 presents VC2, it should make itself VC2's delegate. When VC2 is done and wants to dismiss itself, it should let the delegate take care of that operation. In other words, the thing that shows VC2 should be the thing that dismisses VC2. VC2 should be implemented in such a way that it shouldn't know what presented it, only that what presented it will be in charge of dismissing it.
Two similar answers I've given recently:
Pop-up modal with UITableView on iPhone
call method in a subclass of UIView

I've run into the same problem and I'm trying to recall how I fixed it.
You might try calling:
[self.parentViewController dismissModalViewControllerAnimated:YES]
Or could you have your showMailModalView method handle dismissing the current modal view controller before showing the mail composer?

Related

When I popToRootViewController, none of the views on the stack between the current VC and the root VC get their deinit called

For example here is the problem I'm facing; I have 3 view controllers. When I'm on VC1, the memory is at 9.2MB, when i go to VC2, the memory is at 50MB, and it jumps to ~52MB when I go to VC3.
VC1 -> VC2 -> VC3.
When I get to VC3, I popToRootVC to VC1. But VC2 does not have its deinit called, so when I'm on VC1 (the root view controller), the memory still hovers around 48MB.
What I have tried is, before I popToRootVC, I send a notification to VC2 to remove all of the views I have added to the superview, set these respective objects to nil, clear any arrays, set optional variables I have to nil and then finally removing VC2 as an observer to the notification default centre.
The problem is the memory still hovers around ~48MB, I'm not sure what's causing this problem or how to solve it.
Any idea why this is happening and/or suggestions on what I can do in order to narrow down a solution?

How to switch between two view controllers

I have two UIViewControllers, vc1 and vc2.
I want to switch between them. But before loading the view of the new view controller, I want to destroy/release/remove (I'm not sure abt the correct word to use here) the previous viewcontroller.
For example, when I am switching to vc2 from vc1 ,I want to destroy vc1 completely, so that when I return to vc1 from vc2, vc1 will be loaded from scratch (i.e. viewDidLoad will be executed).
Which type of view switching should I opt for?
presentModal...
addSubview.
I am not using a navigation controller.
Currently I am using the presentModal... method, but when I use dismissModalViewcontroller on the newly presented view controller, it doesn't show up a new instance of the previous view controller. Instead, it shows the already running instance of it.
I want the viewDidLoad method of the previous view controller to run when I dismiss the newly presented view controller.
What exactly needs to happen in viewDidLoad?
You also have viewWillAppear available to you, so it could be that you could move the required functionality there and still use the modal presentation.
See this answer. You can do this with or without animation.
Animate change of view controllers without using navigation controller stack, subviews or modal controllers?

Jumping back and displaying a VC more that 2 layers underneath the top VC

I have the base ViewController which i my main menu(VC1).
From there I navigate to another VC which displays a UITable(VC2). From here i can call
[self.parentViewController dismissModalViewControllerAnimated:YES];
To move back to the main menu. That works fine.
If i load another VC(V3) with displays a UIWebView from VC2 and want to jump back to the main menu(VC1), how can this be done in the best way?
So I navigate VC1->VC2->VC3 and then want to jump VC3->VC1.
My app doesn't have a UINavigationViewController or anything like that.
Many Thanks,
-Code
You could try creating a method in the parent vc (vc2) that you call from vc3 that does the following:
-(void)dismissTwo
{
[self dismissModalViewControllerAnimated:NO];
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
That's untested, but give it a shot.
Its tricky if you used navigation controller you could have popped to root view controller using poptorootviewcontroller.
However in your case if you can implement a delegates for VC2 and VC3. In the delegate for VC3 in VC2 dismiss VC3 and call delegate of VC2 which is implemented in VC1.
So basically the flow is as follows
Create VC1
When you create VC2 from VC1 assign delegate to VC1
When you create VC3 from VC2 assign delegate to VC2
From this point on you can pass messages in a cleaner way between the view controllers.

presentModalViewControllver over a modalViewController works only once

For sake of simplicity I have 3 UIViewControllers named, vc0, vc1, vc2. My Flow of operations is a button in vc0 calls
[vc0 presentModalViewController:vc1]
Then in vc1 I have another button in vc1 that calls
[vc1 presentModalViewController:vc2]
In both vc1 and vc2 I have an X button that calls
[self dismissModalViewController];
Now the first run threw that flow is fine, vc1 is presented modally, followed by vc2 after the correct button presses. Dismissing the views also behaves correctly. However, when I attempt to start the flow all over again I'm unable to present vc2 modally from vc1. Has anyone else run into a similar problem before?
I think You might be missing the allot + init for the view controllers that you want to present

what method does navigationcontroller fire

I have a navigationController and 3 View controllers. VC1 pushes VC2 and VC2 uses PresentModalViewController to display the 3rd VC
When VC2 uses presentModalViewController to show VC3, is the VC3 actually pushed on the navigationcontroller stack?
viewdidload of VC3 is called only 1st time. My goal is to show VC3 with a new imageView everytime. Where do I add the code to do that? viewdidappear and viewwillappear of VC3 is not fired either
It is my understanding that VC3 will be in the view hierarchy of VC2 and not the navigationController. In order to be added to the view hierarchy of the navigationController you would have to push VC3 onto it.
viewDidLoad should only be called once, unless the nib file itself was unloaded from memory, due to low memory. The documentation states that viewWillAppear and viewDidAppear should be called on VC3, so I don't know why they are not.
Update
I just tested and VC3 does have -(void)viewDidAppear:(BOOL)animated called. Make sure that the signature on the selector is correct