a tab bar based app with 5 tabs switching option...how i am suppose to manage memory efficiently?
switching between tab are very frequent i am how to manage this scenario?
or
all tab will remain active no matter what? but thats a bad option...
please describe in detail regarding tab bar memory management
Let UIKit handle it. You shouldn't worry. UIKit will unload views as it sees fit (and you get told about that in viewDidUnload of your view controllers).
So for instance:
You start on tab 1. Tab 1 is the only view controller whose view will be loaded.
You tap on tab 2. Now tab 2's view controller will be loaded and tab 1's view controller is still around.
More time goes on, you tap on other tabs which loads other view controllers.
UIKit notices that memory is running a bit low or it just wants a bit of a tidy up (you have no control over this). So now it will go and unload some of the view controllers' views (but obviously never the one you're currently viewing).
You should of course be a good citizen and release anything you hold onto in your view controller in viewDidUnload that you can easily create again when the view wants to be loaded again.
You don't need to worry about it, unless you're in a low memory situation, in which case the view controllers' views may be released, and you just need to correctly implement:
didReceiveMemoryWarning
and
viewDidUnload
See Apple docs here and here for details.
All View Controllers associated with a Tab Bar Controller are retained by the tab bar controller, but if you're using intense amounts of memory, you can release objects or resources used by your view controller when viewWillDisappear: or viewDidDisappear: gets called. And recreate / reallocate those memory hogging objects when viewWillAppear: or viewDidAppear: get called when the user clicks it into view again.
Related
I have two method to jump from one viewcontroller to another
For presentViewController
[self presentModalViewController:view animated:YES];
For pushViewControlle should use
[self.navigationController pushViewController:view animated:YES];
Which Will be best approach ?
Which will cause more memory leak?
Which one is use if Our Design is like
Introduction view (bunch of slides )-> login -> signUp-> HomeActivityScreen-> Then Bunch of tab bar in it
If you use pushViewController you will automatically get a "Back" button in the navigation bar. If you use presentModalViewController you do not, and generally will have to implement your own controls and/or callbacks to handle dismissing the controller.
Conceptually the modal presentation style is generally used for atomic tasks that you cannot navigate away from (i.e. you either complete the task, or you cancel, and you cannot do anything else within the app until you do one or the other).
If you're wondering why have the difference in the first place, I can't say. Personally I think frameworks that provide a unified API for moving from one controller to another (like cocos2d, or Android) make a lot more sense.
You use modal view controllers to focus the user's attention on a Task. When you push, the user is in some kind of navigation flow, but still has the total application at their fingertips. They might decide to go forward or backward, switch to a different tab in the middle, whatever. When they get a modal view controller, they can't do any of that until the task is completed or canceled out of (the modal view is dismissed)
When you present a modal view controller, the system creates a parent-child relationship between the view controller that did the presenting and the view controller that was presented. Specifically, the view controller that did the presenting updates its modalViewController property to point to its presented (child) view controller. Similarly, the presented view controller updates its parentViewController property to point back to the view controller that presented it.
Modal view controllers provide interesting ways to manage the flow of your application. Most commonly, applications use modal view controllers as a temporary interruption in order to obtain key information from the user. However, you can also use modally presented view controllers to implement alternate interfaces for your application at specific times.
So, from my understanding this one is best option.
[self.navigationController pushViewController:view animated:YES];
Apple handles the memory for both of these through Automatic Reference Counting. Although pushing a view controller might require more memory than presenting the same, the allocated memory is released when popping or dismissing the ViewController. ARC releases the said memory if no strong references are made from within the popped ViewController, or in other terms, the ReferenceCount is 0. So care must be taken so that no strong references are retained to the ViewContoller's objects.
Now whether to present or push a ViewController depends solely on your app design. Read this to get an outline on when to present a ViewController, .
They are two approaches to navigate from one view controller to other view controller.
By default:
- pushviewcontroller: you will have a back button to return to last visited page. your viewcontroller is put on top of the navigation stack. Think like a webpage when you navigate between pages.
- presentmodalviewcontroller: you have nothing to comeback to last visited page. It is usually used for: a pop-up or to change to new branch of navigation.
The use of pushviewcontroller & presentmodalviewcontroller does not produce memory leaks.
For your application flow, I suppose that HomeActivitiesScreen is one of viewcontroller in your "bunch of tab bar". If so, create a viewcontroller that contains that tabbar and make it as root of your application (named RootViewController for example). Then:
When application is launched, you show the RootViewController
And immediately, present the modal view to your "introduction pages", then login/signup. This modal view start with a Navigation view controller structure.
When the user is connected, dismiss your modal view, return back to your HomeActivitiesScreen and refresh contain if need.
Like this, you do not keep the reference to your login/signup screen when you do not need.
I got some serious problems understanding the viewcontroller stack.
When will my app use a stack to save the previous viewcontrollers? Only if I use a navigation viewcontroller or anytime I use normal viewcontrollers and segue modally between them?
So I was just wondering if I use some sort of chained routine for example, like going from vc 1 to vc 2 and from vc 2 back to vc 1. No navigation controller, just modal segues, no unwinding.
Does my app got performance issues because of a stack (which will grow everytime I go around) or doesn't it make any difference?
----updated
So basicly this is my problem. If I went through the routine of the app, the views get stacked everytime I do a transtition.
UINavigationController will retain any controller you push onto it's navigation stack until you pop it back off.
Any UIViewController will retain a controller it presents modally until that child controller is dismissed.
In either case every controller will at a minimum consume some memory until you remove it. Apps which construct ever expanding stacks of controllers are likely to encounter a number of issues including:
you will eventually run out of memory, how fast depends on how much memory each controller uses.
you may see unexpected side effects if many controllers in the background react to the same event.
users may become confused if they change state in an instance of controller 'A', push an instance of controller 'B' on top of it, and then "return" to a second instance of 'A' added to the top of the state. Since they're looking at a new controller and view whatever selection, scroll position, user input, or other state they set on the previous instance may be lost.
developers, including you, may come to dread touching this app.
I suspect that everyone will have a better experience if you view controller management matches whatever visual metaphor you are presenting to the user.
I wonder if there is a way to check if I have too many views stacked in my app.
My app design is:
Navigation controller -> table view (table view works like root VC)
From the table view I can open the menu VC as a modal segue, and form there I can open the login VC as a modal segue, if I log in I end up on the account page like:
Navigation controller -> table view -> menu -> login -> account page
From the account page I can go deeper:
Navigation controller -> table view -> menu -> login -> account page -> list settings page -> edit settings page
Now I have 7 VC's stacked if I count the navigation controller, even though two of them are displayed as modal VC's.
My app does not crash but is this a good way to do it? If I understand it right apps now have to share CPU when running split screen on ipad, so I am not sure if this way is eating too much memory.
Or should I simply make the account VC become the new root VC and reset the stack? And when going back to the table view make that one the new root VC again.
View Controllers are light weight objects. If your concern is memory you should react to memory warnings. E.g. in the viewcontrollers' didReceiveMemoryWarning method. You could release any cached images, remove views if the VC is not visible. Releasing cached objects and images is not always desirable in viewDidDisappear as the user might come back to the screen and you want to avoid reloading everything if there are no memory issues. didReceiveMemoryWarning is the correct place to help the system in freeing memory without sacrificing user experience.
You can of course check how many view controllers are on a navigation controllers stack by checking the UINavigationController's property viewControllers.count.
Resetting the stack to always only have one root viewcontroller is nice but usually quite complex. It is also not really possible inside a navigation controller.
You should use Instruments to check your memory consumption and to verify that you correctly react to memory warnings. Memory warnings can be manually triggered in the simulator.
So when views are stacked on a navigation controller, they are not fully de-allocated from memory, even when they are offscreen. There isn't a strict maximum number of stacked views but you should be smart about it.
If you are concerned about RAM usage then be sure to utilise viewWillAppear and viewWillDisappear to their full potential, performing cleanup operations such as nulling off gesture recognisers and observers, and stopping any listeners that may be running on a background thread. This will reduce the amount of memory your views are using when offscreen; and is good coding practice anyway.
Hope this helps somewhat.
EDIT: Felix also raises a good point about memory warnings, if iOS is concerned about the memory usage of your app it will issue a memory warning which you can react to in the way felix explains.
I wanted to know what will happen if we keep pushing same view controllers again n again. I have 4 buttons, each of which triggers a View. All the 4 buttons are there in all the 4 views.So each time I click a button a view is loaded. So I am pushing a view controller. will this lead some kind of memory management issue or nay other issue? Any other way to handle this? I cant use Tab bar cause of design issues.
I WANT TO BASICALLY IMPLEMENT A TAB BAR WITH 4 BUTTONS. I CANT USE A TAB BAR DUE TO DESIGN ISSUES
This won't lead to any specific memory management issue. Every time you allocate an object it takes up some memory. When you push the view controller you are just allocating a new copy of that object. Whether it's a view controller or a data model or a string, each object takes up some memory. You can easily profile how much additional memory gets used each time you push the view controller, but most likely it is negligible (probably much less than 1kb depending on how much you have in there). I just profiled one of my view controllers and it used 320 bytes. So for simple math, let's say each push takes up 1kb of memory. And an iPhone 5 has 1Gb of RAM. That's enough to hold about 1 million view controllers. So I wouldn't worry about it.
However, if you want to worry about it then you should implement didReceiveMemoryWarning in your view controller and release any unneeded objects.
You can add back btn from your 4 other controllers. On back its removed from navigation stack memory is reclaimed .
If you still have to manual way of managing it, you can use [self.navigationController viewControllers] to check if viewController is there or not and take appropriate decision.
I'm making an interactive book for the iPad and am using UINavigationController to implement the navigation between a page and the next. When a user turns the page, the next page is pushed on top of the navigation stack.
I'm now 15 pages into the app, and the app crashes when I try to go from page 14 to page 15. No error message in the console, nothing in the device's crash logs neither.
Each view controller's scene in the storyboard has UIImageViews displaying images that are between 5MB and 20MB. The view controllers' viewDidLoad method is called just once. The total size of all the app's assets is below 200B. I'm using ARC.
I've ran the app using Instruments' Memory Monitor. The app's Real Memory consumption increases by about 80MB every time a new page is turned, and crashes when it reaches 800MB (the device is an iPad 3).
Why such an enormous memory consumption? Is this because the UIImageView in the Storyboard's scenes cache the images?
What would be the best way to free up memory when you use a
UINavigationController and ARC?
I tried adding setting all the view controller's subviews to nil in the view controllers' viewDidDisappear: method, but memory consumption stayed the same.
When you use a UINavigationController, each ViewController you push stays in memory forever (well, until your app exits) unless your user presses the back button on that particular ViewController. It keeps a stack of ViewControllers - with the visible one at the top.
So the simple answer is don't use a UINavigationController for this.
I'd suggest building your own ViewController that 'knows' which is the next and previous pages and manually loads and removes them as and when required. This way you can ensure that you only have one page in memory at once (except for during the transitions - maybe you could use this animation for the transitions http://cocoacontrols.com/platforms/ios/controls/xbpagecurl).
You probably don't want to use a UINavigationController for this purpose. You really want one view controller to manage all your pages and render the new page on the same view while removing the old.