I am using RouteMe's library and services to display maps.
The main ViewController holds an *RMMapView that inherits from UIView. Basically it just fills up with tiles.
When my app goes to background, and after a while, after other apps are loaded into memory usually, comes back to foreground, The main mapView goes completely black and I can't see anything except for my UI.
(I guess due to lack of memory)
How can I prevent that from happening ?
Thanks!
you cant prevent a Memory warning from happening, however if you are 100% sure that you cant handle the memory warning in some view controller and to stop the call to viewDidUnload remove the implementation of didReceiveMemoryWarning in your view controller
Please note that disabling the viewDidUnload is not recommended, you should reflect about your memory usage and present a better memory management technique
Related
I have created an app with 12 view controllers and its got a lot of graphics ( image files )
When I launch the app, I notice the memory goes up as I move through the view controllers.. once I have moved through all the controllers the memory is 530Mb
so my questions are :-
a) is this a lot of memory to be using
b) should I be worried
c) how can I remove view controllers from memory as I navigate round.. for example I have a view controller for on boarding , but once some clicks on skip or get started, I segue to the next view controller, so in theory it doesn't need to be loaded any more..
Thoughts ?
Im running on an iPhone 7 Plus which has 3Gbm, but want to be able to run the app on other phone models from iPhone SE onwards. however I notice the memory profile is about 50% no the iPhone SE but assume thats because its not loading the x3 images as per plus phone
a) is this a lot of memory to be using
lot is a relative term and whether 530Mb is lot or not completely depends on what app is doing and what kind of app it is! If its a game with rich graphics I wouldn't be bothered much but if its a plain utility app I would be concerned!
b) should I be worried
Memory getting accumulated/increasing as user loads various screens of app is a very common scenario. You should be bothered if it keeps increasing and never comes down. Every time a VC loads it might load, heavy graphics with it or might allocate large amount of variables and consume lots of memory to perform its function. Which is quite fair. But once user pops the VC from applications navigation stack all the memory allocated by the VC should be returned and total memory consumed by the app should come down. Ideal memory foot print would look like a wave where it reaches peak and comes down once VC pops out. If thats not happening you are in trouble :)
c) how can I remove view controllers from memory as I navigate round
Use proper navigation techniques. Don't keep pushing the VC's to navigation controller stack unless you actually need that VC instance to be retained in memory. All VC's pushed to Navigation stack will continue to be kept in the memory till either user kills the app or iOS decides to kill the app on receiving memory warnings.
Write deinit/dealloc in each VC and make sure it gets called every time user pops the VC by either tapping back button if its pushed or by dismissing VC if its presented modally. Ensuring each VC's deinit gets called is the best way to ensure VC does not hold up any unnecessary memory.
Make sure none of your VC has code which results in retain cycle and retains the objects in memory forever. Example : If your VC declares a block and holds the strong reference to block and if you pass self to block your block and self will never be released. Classic example of retain cycle. Make sure your code does not create such dead locks
Never hold anything strongly by using either strong/retain unless its necessary.
Use instrument to find the memory leaks and reference counts of each objects just to make sure there is no memory leaks in ur app.
I'm at a point in the development of my little app where I'm implementing didReceiveMemoryWarning and such, but I feel like I don't have a good grasp on the best way to test what I'm implementing.
First off, apparently in the simulator, didReceiveMemoryWarning isn't triggered for apps that aren't in the foreground until that app is brought back into the foreground, according to this question - actually, that matches my own experience, but I was prone to ignore it because it doesn't really make sense. (Why would I want to delay clearing up my memory until I'm coming back into the foreground and probably about to need that data again?) Does this match the behavior of actual hardware? If so, does it make sense to cleanup tasks in applicationWillEnterBackground in addition to didReceiveMemoryWarning?
Second, generally, what is a good strategy for triggering the "Simulate Memory Warning" menu item in the simulator in such a way as to trigger memory warnings in a manner that they're likely to happen on the actual hardware?
Q1: Does this match the behavior of actual hardware?
A: Yes, the simulator and the actual device behave the same in this regard (e.g. if your app is suspended and is not running a background task, it does not receive applicationDidReceiveMemoryWarning).
Q2: Does it make sense to cleanup tasks in applicationWillEnterBackground?
A1: Only insofar as that your app must prepare itself for a complete restart. If your app remains suspended and the user does a lot of things with other apps, your app may become fully unloaded - even though the app may still be visible in the task switcher, when the user activates it the next time, your app delegate will receive application:didFinishLaunchingWithOptions: (not applicationWillEnterForeground:).
A2: I wouldn't bother with cleaning up memory, but you should make sure that by the time applicationWillEnterBackground has finished, any user preferences and other stuff are saved so that the app knows where to take up again when it is activated the next time.
Q3: What is a good strategy for triggering the "Simulate Memory Warning" menu item?
A1: I doubt whether a general strategy can be formulated since every app is different.
A2: To use a specific case: In my app, I don't use the app delegate's applicationDidReceiveMemoryWarning to relieve memory pressure, instead I rely on the fact that when a memory warning is sent, iOS also invokes viewDidUnload on certain view controllers that are not in use. Therefore I generally use the memory warning simulation to test whether my view controllers' viewDidLoad and viewDidUnload are balanced correctly.
A3: Concrete example: My app uses tabs, so a favorite scenario of mine is to 1) display the tab with the view controller (VC) under test; 2) navigate to a different tab; 3) simulate the memory warning (iOS invokes viewDidUnload in the VC under test); 4) navigate back the original tab (iOS invokes viewDidLoad in the VC under test).
A4: If you want to use a similar approach, then you have to figure out for your app which views might be unloaded by iOS. In my (limited) experience these tend to be views that are unrelated, such as views on different tabs.
Here's my answer to your second question - it also kind of answers your first question:
I've used the "Simulate Memory Warning" feature to effectively reproduce issues where a child view controller consumes enough memory such that its parent must free up resources.
For example, consider a child view controller that displays the camera/photo library (i.e., UIImagePickerController)). This uses a significant amount of memory. If the picker controller consumes more memory than is available, the parent's view controller will be unloaded, and once the parent view controller is shown again (when the child is popped), the parent's viewDidLoad will be called again. This means that any variables set in viewDidLoad will be set again, potentially with memory leaks or bad pointers.
The "Simulate Memory Warning" helps to find these problems. You can go into the child view controller, select "Simulate Memory Warning", then pop the view controller and check for problems.
Note that the "didReceiveMemoryWarning" is more relevant (imho) to let you know it happened than actually trying to release memory at that point.
I am writing an iPad app which uses an AVPlayer to display a video. There's buttons to jump to various parts of the video, and when the user rotates the device, I change the size of the view which holds the AVPlayer layer.
My problem is that after a certain amount of device orientation changes and jumps around the video, the app crashes.
I have NSZombie enabled - this doesn't break.
I have a breakpoint enabled in my code to catch exceptions - this doesn't break.
I have run instruments and the code isn't leaking.
Allocations simply shows the "Overall Bytes" growing and growing with every action until it hits 14 meg and the pad crashes.
I feel like I have no way of getting to the bottom of this. Am I missing some trick to solving this? Does AVPlayer need some special treatment when being released?
ANY HELP, MUCH APPRECIATED.
Use instruments to check your Allocations. I recently had a very similar problem where there were no memory leaks but my Overall Bytes kept growing every time I launched a particular ViewController (and it would eventually crash).
It turned out that the ViewController itself was a strong reference as a delegate to another class (oops) and each time I dismissed the ViewController that other class still had a reference to it. Therefore each time I launched and dismissed this ViewController I would create another instance of it that would never die (and never leak).
Your exact problem may be different but you should be able to see the reason for your Overall Bytes growing by checking out your Allocations.
My application which is a UITabbar app has eight tabs. one tab for playing Audio, one for Playing Videos, one for Books(Leavesview is used for opening jpg image pages),one for Gallery.....so on.
So, Once I open all tabs the app throws memory warnings and crashes.
Then I did this: In each tabs viewController, I have allocated everything(views, imageViews.....) in ViewDidAppear method then I did removeFromSuperView and release in ViewDidDisappear method.Even then the problem persists.
Using Activity Monitor I observed that the app crashes when it exceeds 128 MB of Memory.
Each tab's ViewController is Occupying around 40MB memory. Even though I release everything in the ViewDidDisapper of the tab the memory is not freed but kept on increasing.
Is there anything regarding memory I have missed. Please Help me resolve this , Thank You.
I have noticed that when instantiating a UITabBarController it loads all it's dependencies and is really stubborn when trying to release an entire UIViewController. I've done a few things to combat this when I've had high memory UIViewControllers attached to a UITabBarController. What I suggest is only releasing the memory hog controls associated with each UIViewController on the ViewWillDisappear and re-Instantiating them on the ViewWillAppear rather than trying to release the entire UIViewController. Typically this is bad practice because you want to recycle as many of the controls as possible but if you have to stick with the UITabBarController this is the only way I've been successful.
If I misread your post and you aren't trying to release the UIViewController the I would need to see some code to figure out why things aren' releasing on ViewWillDisappear.
I have a problem with UIWebView. I am using this component for loading normal web pages on iPad/iPhone. UIWebView is presented in modalViewController. Some pages are very memory hungry and some also have Flash content.
The problem is that sometimes on some pages I get memory warning
Received memory warning. Level=1
When this happens and when I close this modalViewController (which has page loaded in webView) than the previous view reloads itself automacially - method viewDidLoad is fired again.
I suspect that some pages in UIWebView consume to much memory and than application release memory of its views, but does not crash.
Is there a way to limit memory consumption of webView or is there any other way to avoid this memory warning?
Thanks!
You have very little control of the memory usage of UIWebView objects. You also have very little control of the overall system memory usage. So there is no way to avoid memory warnings. iOS expects your apps to behave properly when receiving memory warnings, so your viewDidLoad method should be written to handle rerunning after a memory warning.
The only things you can do to limit the memory usage of a UIWebView is to have it view simple web pages. It looks like from your question, that's not an option.
Edit: viewDidUnload is called during low-memory conditions. This method is expected to free up anything that's easy to recreate in the viewDidLoad method. Don't release the state information you want to show the user when this view is returned to the screen. Then in your viewDidLoad method check all the objects you create. If they are nil, they need to be initialized, otherwise this isn't the first time your viewDidLoad method was called, and you shouldn't initialize your objects agin.
In other words: viewDidUnload handles low-memory situations and viewDidLoad should not assume it is run once.