General doubts on Navigation Controller - IOS - iphone

I have some general question about navigation controller. I have pushed a table view with navigation controller. (now table view showing) If I click on back button of navigation controller it brings me back to main view, now the memory allocated for table view will get released automatically. Do we need to do extra?
thanks in advance.

In general, as long as you don't maintain a reference to the object, you can safely assume Cocoa Touch will do the right thing. When things aren't drawn on the screen, the APIs generally don't just hold on to them for no reason, so if you're not holding on to them either you're fine.
"Holding on" in this context either means "keeping a reference to" if you're using ARC or "not releaseing" if you aren't.

Before ARC: When you add a UIViewController to the navigation controller's stack you need to release the view controller after pushing the it onto the stack.
No need to do this if your project is ARC enabled. Read up more on ARC.

Related

using dismissModalViewControllerAnimated without deallocating modal view controller

I'm creating an app using the iPhone Utility App framework, and I'm trying to use a navigation controller on the flipside view, as there will be a lot of drilldown options on this view. When I'm done with this view, I call the following code:
- (IBAction)done:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
When I dismiss this view, I want to be able to go back to the place in the navigation I was currently at when I reopen this view again. However, when I dismiss this view using this method, the vc gets deallocated, therefore the menu starts back at the beginning when I try to go back to the menu.
Thoughts?
You'll need to retain a reference to the object (I'm calling it the options controller). I would say the easiest way is to create an iVar in the presenting view controller that references the options controller. Then, when you go to present the options controller again, just present the referenced options controller rather than creating a new controller. If different view controller objects can present the options controller, you'll need to either pass that reference around, or store it in some object that all the other view controllers have access to.
Hmm not much code so maybe I'm misunderstanding your setup, but...
You could use the AppDelegate to store (as a property) your current position (index) in the views collection of the Navigation controller, and then write a method that pushes to that (stored) position when you re-visit it later.
Might be an easier way to do it though..
So what you want is to flip from a view to another view? If you want to keep the navigation bar status between flipping, I recommend you use only one view controller to control this 2 views. you can use + transitionFromView:toView:duration:options:completion: of UIView to flip views.

Passing a UIView to next UIViewController that gets pushed on navigation stack

I have an app where I have an imageview displayed within a UIView that the user has scaled and moved around, and I'd like to pass this exact same imageview to the next UIViewController that gets pushed onto the navigation stack. What is the best way to go about doing this? Do I have make some sort of deep copy?
controller.imageView = imageView;
There's not much special about this. The only thing you need to do is to add the view to your view hierarchy. Views can only have a single superview, so when you add it to a new view hierarchy, it is automatically removed from the old view hierarchy. The only tricky thing is when you pop back up the stack. Do you expect the view to still be available in the old view controller? (It won't be.)
In general, I'd tend to recommend passing the parameters rather than the actual view (i.e. the image and its transform). This gets rid of any issues going up or down the stack, but either way can work.
Give the view reference to the next controller, retaining it.
You could have some problem to deal with its bounds or frame, but if you just want the same, that should be ok.
In the new controller, get that passed view and add it as a subview of your main view. Don't forget at the end to remove it from its superview, and to release it before returning to the previous controller.

could strange UINavigationController nav bar behavior be due to memory leaks?

I'm getting strange navigation bar behaviour, for example when I hit back button the screen displayed is the previous screen, however the Navigation Bar items do change. So I'm left with screen A, but with nav bar buttons for screen B.
Could this be due to memory leaks? I do note with my app still:
This behavior seems to happen:
immediately if I trigger memory
warning via the simulator menu, or
on a device after it has been on
for a while [without being killed
and then restarted as an app].
I do have some memory leaks I'm
trying to clean up (i.e. Profiler
highlights items in "leaked blocks"
section)
Any tips on fault finding root cause of why pushing a back button would end up in a weird state? e.g. screen on previous parent view, but nav bar items don't change...
UPDATE - I have finally removed the memory leaks in my app, however I note the nav bar issue still remains. I guess this doesn't confirm the answer to my question is NO in general, but in my specific case it wasn't the memork leak...
From Apple:
The navigation controller updates the
navigation bar each time the top view
controller changes. Thus, these
changes occur each time a view
controller is pushed onto the stack or
popped from it. When you animate a
push or pop operation, the navigation
controller similarly animates the
change in navigation bar content.
Based on this, I would start by looking for a bug or misconfiguration in your view definitions. Check for any InterfaceBuilder warnings if you defined your views via NIBs. Make sure your view hierarchies are correct in both UIViewControllers. Also check for possible bugs in your view life-cycle methods: viewWillAppear:, viewWillDisappear:, etc,.
Actually, it would be nice if you could post some screenshots and/or code. Thanks!
Any view that is not currently visible and only retained by it's view controller (as a part of the view property of that view controller) will be released (along with any non retained subviews) when a memory warning occurs.
Chances are you are creating the view as a part of init, and not retaining it in the controller (simply letting the view socket hold it from releasing). One way around this is to create properties for the views you create (nonatomic, retain), and after creating them and autoreleasing, assign to those properties, don't forget to assign those properties to nil as a part of dealloc to avoid leaking. Another way is to create your custom view elements in viewDidLoad as opposed to init.
Hard to say without code example from the offending views :)
I've seen something like this happen after calling -[UINavigationController setViewControllers:]. You might try not doing any programatic manipulation of the navigation controller's view controller beyond calling -[UINavigationController pushViewController:animated:].

How to tell if view has appeared via popping or not?

Using a UINavigationViewController, how do I find out how a view has appeared?
The view has either appeared in a straightforward manner, as the first view in the UINavigationController stack. Or it has appeared because a second view has been popped and the first view has revealed itself again. How do you find out which of these happened?
The only reliable way to do this, as far as I'm aware, is to subclass UINavigationController and override the UINavigationBarDelegate methods:
– navigationBar:shouldPushItem:
– navigationBar:didPushItem:
– navigationBar:shouldPopItem:
– navigationBar:didPopItem:
Don't forget to call super, of course.
Simple approach is to add a property to your RootViewController to track whether or not it has pushed another view onto the navigationController.
-(BOOL)hasPushedSecondView;
Initialize to NO in your init method.
Before pushing secondViewControllers view onto the stack, update the property to YES.
In viewWillAppear, check the value and update your view accordingly. Depending on how you want the application to behave you may need to reset the hasPushedsecondview property back to NO.
you could take a look at the leftBarButtonItem or backBarButtonItem, based on how your application is written and determine how the view appeared. If it is on top, unless you have a custom leftBarButtonItem, there would be no object there.
You can determine this directly via a couple of methods on your UIViewController subclass.
From Apple's documentation:
Occasionally, it can be useful to know why a view is appearing or
disappearing. For example, you might want to know whether a view
appeared because it was just added to a container or whether it
appeared because some other content that obscured it was removed. This
particular example often appears when using navigation controllers;
your content controller’s view may appear because the view controller
was just pushed onto the navigation stack or it might appear because
controllers previously above it were popped from the stack.
The UIViewController class provides methods your view controller can
call to determine why the appearance change occurred.
isMovingFromParentViewController: view was hidden because view controller was removed from container
isMovingToParentViewController: view is shown because it's being added to a container
isBeingPresented: view is being shown because it was presented by another view controller
isBeingDismissed: view is being hidden because it was just dimissed

iPhone - UINavigationController, reuse views?

The root question is "how many UIViewControllers can you push on the navigation stack?" without causing memory warnings or earning a watchdog termination.
Suppose I have an application that is basically a database for three entities where each can have a relationship with some other entity, and the relationship is shown on a UIViewController. Users can follow those relationships and each one brings up a new controller - If the entities are A, B and C and A->B->C->B->C->A then each kind of view is on the stack twice. I understand how to push and pop, how to push back to a particular controller, and I think rather than just extend the navigation stack indefinitely it might be best to reuse a view controller in the navigation stack.
To do this, every time I wanted a FirstEntityViewController I could scan the navigation stack to find an object where [self isKindOfClass:[FirstEntityViewController class]]; and then call methods designed to rejig that view for what I currently want to see - just refreshing the data in the same way you do when reusing a UITableViewCell.
This is fine except for the effect it might have on the NavigationController. If I use UINavigationController:popToViewController:animated: I think it is going to discard everything above the view I'm popping to, including the view which the user expects to find on tapping "Back" in the navigation bar. So user taps a relationship, taps back and goes "huh?"
If I remove the matching controller from the navigation stack and then pop it on to the top of the stack the back behavior remains OK as long as the user doesn't go back as far as the instance of FirstEntityViewController that was moved or else again navigation will seem inconsistent.
Is the right solution to remove the controller from the stack, and somehow hold a place in the stack so that when the reused controller is popped it can be replaced back where it came from? Should I maintain my own list of view kind and data display so that when popping I can replace the view below the view about to pop to, staying one step ahead of back navigation?
Or is that just getting too complicated? Is there no need to even worry about this situation because the OS reuses much of the view controllers in the same way as UITableViewCells are reused, and there is no real memory or performance impact in having a 50-deep navigation stack?
ViewController instances remain in the UINavigationController's stack, but any view except for the top view may be unloaded at any time (the view controller is notified via the viewDidUnload message).
In other words, the views underneath the top view do not hang around and will eventually be unloaded in low-memory conditions, so there's no need for you to attempt to re-use your view controllers.
Last I checked you can't push a viewcontroller that's already on a navcontroller stack back onto it again. You'll have to create a fresh viewcontroller and push it onto the stack and each back button will pop that one off the stack. The best you can do is make a cache of viewcontrollers and dole them out as-needed -- as long as they're popped off the navcontroller stack. But it probably won't buy you much by way of memory savings.
UITableViews are a bit different in that there's only a relatively small number of cells in view at any given time and as soon as the cell goes offscreen it's removed and returned back into the pool. If you can guarantee that the maxdepth of your chain is fixed, then you can pull a similar windowing scheme. If not, you may have to stick with going deep and be vigilant about releasing memory as soon as you can.