UICollectionView not release memory after select a new button - swift

I'm working on a note app that has a collection view of notes, and taping each cell will lead the user to different note. In the case of my app, each note is essentially a PKCavnasView that inherent from ScrollView.
What I found is that when user navigate back to collection view and select a new cell, the memory used by the previous note is not released. So as user navigate between different notes, the memory usage will soar up.
What's more of a problem is that when the app goes to the background, all the memory is still not released.
What I'm wondering is that, will the navigation controller automatically release the memory of each tap to different cell? If not, is the autorelease pool the solution here? If so, where should I put the autorelease pool.

Related

Memory not released when storyboard disappear

In my app there is a Login.storyboard and Dashboard.storyboard. Once I tap login button I am presenting Dashboard. When I tap logout button, all I do is perform unwind segue to Login. My DashBoard.storyboard disappear, but my memory allocations still are the same. When I login again, I allocate a new objects, when I logout, nothing changes. Doing just two things (login (present storyboard), logout (unwind)) I only increase allocations, instead of decreasing it while logging out.
How to fix this? Is it normal?
In my app there is a Login.storyboard and Dashboard.storyboard.
If literally true, that's your problem. You don't need two storyboards here - just one storyboard with two view controllers (scenes). If you're going to use two storyboards, then you just have to live with the extra memory usage that this entails.

How to release entire UINavigationController

I have an iPhone application, and I have included a virtual "timeout" for being in the background. When it enters the background, I make a timestamp. When it re-enters, i compare the current time to the timestamp. This all works great.
What I want is for the application to basically reset like it was just launched. Everything in my application lives inside of a UINavigationController, so I thought I could just release it and everything inside, then reallocate it and start over. Is there a right way to do this? I have a feeling that if i just "release" the UINavigationController, all of the ViewControllers inside will just leak into memory.
You can just release your UINavigationController, and if your ViewControllers are only retained by your UINavigationController, which should be the case, then they will also get deallocated.
You may reset your model data manually and then return to start screen of your app by
[self.navigationController popToRootViewControllerAnimated:NO];
To do this in a sensible way you need to reset your controllers and data model to the state you want (e.g. as if your app was just launched). I'd also do this in a way that looks natural for your users. Something like the following:
Load a splash screen view (or something temporary) in the main app window.
Release your navigation controller (more generally, release the top level controller owning the view previously added to the window). this will release all associated controllers and views assuming you haven't retained them anywhere else.
You may also need to handle any modal views that were displayed when your app went into the background. You can either dismiss them automatically when the app goes into the background or keep state around to dismiss them when the app resumes and you are resetting it).
Reset your data model to the state you want
Recreate your navigation controller and add it back to the window and release the temporary splash screen.

iPhone: Good idea to dealloc and rellocate UI items when switching views?

Suppose I have 2 views. In the first view, I allocate memory to displaying many UI components such as an UILabel, UIImages, etc.
Suppose the user navigates to the next view (via UINavigationController)
Is it OK to deallocate memory assigned to displaying UI components in the first view and then initialize them again once the user goes back to the first view (in viewFirstLoad or the appropriate function)?
It seems to me if you don't do this, then memory will keep on increasing the longer the user uses your app in that particular session.
Is this not allowed? frowned upon? impossible?
It is perfectly normal and in fact, that functionality is built in standard UIViewController - when controller is not displayed its view may be released from memory and you can release all its subviews (e.g. retained through IBOutlet references) in controller's -viewDidUnload method.
When controller needs to display again it reloads its view again.
It depends. Generally, the rule of thumb is that you should free objects that you don't need. If your view is just a view, then yes, I'd release it and all of its subviews. If your view has data that was obtained through a lengthy retrieval process (e.g. a web service call), I'd probably hold onto the data somewhere so that I don't have to go back out and retrieve it when the user goes back to the first view.
To clarify a little: Apple recommends you display data specific to a view in it's -viewDidLoad method, such as setting text on labels. Then, in -viewDidUnload you should release (or nil outlets of) the view objects you setup in -viewDidLoad. It's critical you implement -viewDidLoad, as the base UIViewController code checks that it's subclass actually implements -viewDidLoad before it assumes it can unload the view (and therefore call -viewDidUnload). Failing to implement -viewDidLoad results in the controller thinking it can't recreate your view at a later time, and so it doesn't unload the view from memory. A developer I know experienced this same problem, took forever to track down.

How to Handle an Indefinite Amount of TableViews in an iPhone drill-down app

I've Created a UITableViewController subclass. Do I only need one controller? Do I just instantiate multiple instances of that one subclass?
The iPhone App I'm building will start with a Table of a list of people. If the user taps a person, a new table will be pushed in with a list of Companies they've worked for. If the user then taps a company, they'll see a list of Job Positions. And if they tap a position they'll see a list of people holding those positions.
This could go on forever, and the user could always back up the list.
The App Delegate instantiates the Navigation Controller and the Table View Controller and then pushes it onto the Navigation Controller. But when a user taps a row, now the TVC is creating another TVC.
Is that right or should the
AppDelegate be instantiating all
TVC's? Or does it work out since
they all get pushed onto the Nav
Controller anyway?
Does each Table View instance
need to have a different name or can
they all be called 'mainTVC' or
something like that?
tableViewController *mainTVC = [[tableViewController alloc] init];
Won't I run out of memory? Do i
need to start dropping Table Views
when they're 2 or 3 levels away from
current, and then re-create it if
the user backs up to it?
No need to create multiple TableView's, what I've done in the past is simply re-bind to a different datasource. So keep one TableView and have a datasource for people, then companies, etc...
I'd create a view controller for each type. Presumably you'll want to have special display characteristics like a custom tableview cell to display job positions slightly differently then you would people names.
Other then that, #Ben Gottlieb's answer should work quite well. Use lots of view controllers and handle the didReceiveMemoryWarning: method.
One more thing, if the user drills down so far that you want to say they'll never go all the way back (sort of like having an undo stack) you can use the setViewControllers:animated: UINavigationController method to reset the stack to a certain size (say 15 to implement an 'undo buffer' of 15). With this method you can make sure that the first view controller is always your root view controller and the rest are all drilldown instances.
Option number (2) looks good. You can push quite a lot of view controllers onto the stack before memory becomes an issue. The system will clean up most of the heavyweight memory hogs (ie, the views) in the didReceiveMemoryWarning: method. If you're creating a lot of in-memory structures, you may want to clean them up in that method (be sure to call the inherited method).
To answer your third question, as long as you don't have huge data stores in memory, memory shouldn't be an issue. You SHOULD NOT under any circumstances "drop" tableviews - this would lead to crashes(and there's no way to do non-FILO additions/removals to the navigation stack anyway). Under memory pressure, you should only free "nonessential" items like caches. However, this shouldn't be an issue.
Also, if you have more than 3 or so levels, chances are you need to rethink your UI. If users are drilling down 10 levels, it will be tedious to navigate the stack back.

iPhone memory consumption

I have developed an iphone application that opens to a tabbed view with the first tab being a uinavigationcontroller. Within that controller is a uiviewcontroller that contains a uitableview. There are 2 items listed in the tableview. When I select one or the other item, it displays yet another uiviewcontroller with dynamically generated uiviews.
When I press the "Back" button at the top of the navigation control, to return to the previous uiviewcontroller (that contains the tableview), and then I select 1 of the 2 items in the uitableview again, it eats up almost 2M of memory according to Instruments. This occurs each time, until it reaches about 24M, and my application crashes.
I am registering no leaks whatsoever.
Is there something I need to be doing when the "Back" button is pressed to release the memory allocated to the uiviewcontroller.
I'm not sure how far you are in iPhone development, or how much you know about the memory management, but it could be a reference counting issue. Remember: If you call alloc or retain, you need to call release, and never call release on something you haven't alloc'd or retained.
The navigation controller retains all view controllers pushed onto its stack, so if you ensure that such view controllers are autoreleased or that you otherwise have no claim on them (e.g., alloc, push, release), they will automatically be released when popped.
If you're doing this and you're still losing memory, perhaps you are over-retaining the your custom views from their view controllers?
It's difficult to say without seeing code, but one thing that might be useful is implementing -didReceiveMemoryWarning on all your UIViewControllers and logging details of them -- then if you see a memory warning from a view controller you think should have been deallocated, you have a starting point for further investigation.
Also, have you tried the Clang Static Analyzer? The Leaks tool is useful, but gives plenty of false negatives. The CSA is no panacea either, but it catches some things Leaks misses.