Something odd is happening with my view controllers. When an applicationDidReceiveMemoryWarning is posted, it removes all views from the stack other than the visible view (a second level view) which is expected behaviour. However, if I then navigate back to the root view, it also has a back button that navigates back to itself. From there on the app views behave very oddly to the effect that the app is useless.
More strangely the exact same second-level view (with no memory leaks) can work fine without any memory warnings, yet sometimes on app launch cause a memory warning and therefore the navigation issues. The view holds all the same controls and data as before, yet can sporadically be too much for the device to deal with. Is this something to do with memory available on the device at the time of launch? This only seems to happen on hardware.
Any ideas?
I have found the problem - and it's my code after all.
On application launch I load my root view controller, then in my root view controller's viewDidLoad method I am telling it to load a second view if a condition applies.
When the memory warning occurs, it's recreating the root view controller when exiting the second view, and then creating the second view again whilst still showing the root view.
This then causes the navigation to go mental.
I am by far no expert on memory issues. But odd behaviour after this kind of things indicate to me that the removing of memory did not happen consistently. Maybe some references are still kept and the app thinks these are valid references, but in reality, the memory is no longer allocated. It could also be possible that the memory is reallocated with the old references still in place which could also lead to strange behaviours.
Hm, i can not offer much advice here, only that you could check references to unallocated areas
Related
I'm in the process of learning Swift. I wouldn't say I'm a novice, but I'm sure like many learning online I have missed a lot of fundamental steps to understanding what's really going on.
After getting pretty far with my app I am now seeing that my memory management is very poor. I am using SDWebImage caching which is definitely impacted by GIFS, but more to the point I am now learning about retain cycles and deinit.
Could someone please explain why a ViewController inside a UITabBarController deinit is never called?, why this isn't a bad thing? (unless it is) and just general advice/direction on memory management when using a tab bar controller. I have looked into retain cycles and why they are caused and fixed, but that doesn't seem to be my issue according to xCodes instrument tools.
Any advice would be much appreciated
Thanks.
A tab bar controller does not create and destroy the view controllers (tabs) it manages. It holds onto all of them so the user can switch between them as needed. Thus the view controllers from the tabs persist as long as the tab bar controller persists.
If your app's root view controller is a tab bar controller that never goes away, neither will the view controllers for the tabs.
If, instead, you create a tab bar controller and push it onto a nav stack, or present it modally, the tab bar controller will be released when it's popped/dismissed, and the view controllers will then be released as well.
Also, another reason an object may not be deinitialized is because of references. Since you are just starting Swift, I strongly suggest that you look up tutorials on Reference cycles, ARC (automatic reference counting) and memory leaks. They’ll teach you about
weak var
And the proper time to use it. When starting, I’d say it’s not too important, but they are valuable later on when trying to get a job in software development.
To address some performance issues, I started recycling some view controllers. However, the performance benefit of re-using a recycled controller's view is only present if that view has been drawn. If, for, example, I want to pre-populate the recycle queue with a controller but never place its view on screen, I get no such benefit.
How can I force the controller's view to be 'pre-rendered' and added to my queue such that when it is recycled I receive the performance benefit I am seeing from my other recycled controllers? I know that a controllers's view is created when first needed, but even adding the view and immediately removing it (before the parent view is displayed) doesn't seem to do it.
My first thought on a quick and dirty way to do this is to just set the controller's view to hidden, and still have it "drawn" to the screen.
That bring said, I'm curious as to what the "performance issues" are that you're observing. Depending on whether the creation of the UIViewController itself, or the UIViews that are causing a problem, then there may be a better overall solution to the problem.
I have an iPhone app that has a 4 option menu, and allows the user to switch between view controllers quickly. So I thought to make the experience smoother, every time the user switches between view controllers, the from view controller is released right away, and the to allocated. And the user will most likely be doing a lot of switching. Is there a better way to handle memory here than to keep releasing and allocating the same view controllers over and over again?
View controllers aren't expensive. It is ok to alloc and release them. However the views can be expensive. When memory is low, the system tries to unload the views of the view controllers which are currently not visible. Your app should always be aware of that. Release expensive objects in viewDidUnload, i.e. IBOutlets and data that can be recreated.
If you experience performance issues you should hold all 4 view controllers in memory. So the views will be loaded faster. iOS takes care of unloading the not visible views (when appropriate).
If it's the user doing the switching, time spent in dealloc and/or alloc is completely insignificant, bar any extremely time-consuming operations like loading tens/hundreds of images, etc.
In short, both an on-demand and a cached solution will have some tiny advantage over the other. Your users will not notice the difference though.
It sounds like you might have been better off with a tab bar app?
If memory is your main concern then it sounds like you will be loading and unloading a lot which will be a slower experience for the end-user.
If you use a tab bar controller then the views in unused tabs will be automagically unloaded if memory is needed. and loaded again if/when necessary.
When I run my app on the simulator, then I go Hardware->Simulate Memory Warning it causes my view to go blank (I just see white). Does anyone know how I can make it NOT do that? -- I don't want an actual memory warning to make my screen blank.
Thanks
I'm having the same issue. I have an application where you're presented a login screen, which pushes under a NavController a main menu. Every selection in the main menu then pushes a new view controller. If i get a memory warning when under a menu item, going back to the menu displays a blank view.
This is probably more of masking the symptom than fixing the problem, but by overriding my main menu's didReceiveMemoryWarning message with an empty one (so that the super version isn't being called) stopped the view from disappearing.
I like this better than overriding setView (as recommeneded here) because you don't get the pesky performance warning about "-viewDidUnload caused the view to be reloaded."
I got the same issue right now and I solved the problem.
In my case I got this lines inside the mainViewController's code:
- (void)loadView {
[super loadView];
}
after simulating a memory warning the system call didReceiveMemoryWarning and you can check that viewDidUnload is called immediately after and if you use loadView inside your code the class call it to reload a brand new page that replace your old view.
This cause a blank screen.
So to solve the issue I just commented the three line above.
bah, it was mainly because I set my navigation controller incorrectly
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.