My app utilises tableviews that all have associated UIImages.
I show my UIImages in the app using:
cell.foodImage.image = UIImage(named: foodImageArray[indexPath.row] + ".jpg")
I know in objective c something such as
UIImage initWithContentsOfFile
Could be used in order to keep the memory footprint low.
Is there something like this I can use in swift?
UIImage(named:) caches once loaded image and keeps it in run-time until app quits or 'out of memory' notification from system, on which cache somehow cleaned up automatically.
Thus it is better to use this constructor only for small images, which are either always visible in UI or used often.
For other cases (probably your table view case is here) it is better to use UIImage(contentsOfFile:) constructor with implemented some in-app cache logic to keep it for some workflow only but clean when go out it (other mode, scenario, etc. including force cleaning for 'out of memory' notifications)
Related
How can I track down abandoned memory if in Xcode Instruments don´t show my custom classes?
So I can see the heap is growing after I perform an action with my app (open a view and go back to the previous in my case) and I could fix some memory issues before by tracking down my mistakes in my code.
Now however, I only see things like in Generation N (= Heapshot N), non-object and I don´t know any more how I can fix the leaks. The responsible caller (not seen in the screenshots) also show no own classes/objects.
Edit
The Showing View is a UIWebView. I searched the web and found rumors that UIWebView doesnt properly releasing data. Could that be the issue? I can´t find any solution.
UIWebView is notorious for causing memory issues.
Make sure you set the UIWebView object's delegate property to nil if you assigned an object to it as documented in the class reference. You can do this in dealloc.
Cleanup the web view in viewWillDisappear:animated: by stopping URL loading with a call to stopLoading and/or setting the HTML string to nil by calling loadHTMLString:baseURL: to workaround any memory being held.
I have a few tabs in my app. I am currently facing an issue whereby my pages gets unloaded whenever the memory gets low (especially if I bring up the camera in my app).
Is there anyway to mitigate this and prevent unloading from happening? Or is there any way to intercept the unloading process so that something can be done instead of allowing the page to be unloaded?
You should not prevent view unloading, if the application runs out of memory, it MUST free memory, or else your app will simply be killed by the system. You should really cleanup as much memory as you can, as well as views.
Also, views are only there to display data, if the view is unloaded it's only in one specific case: there was a memory warning and the view didn't have a superview (not visible to the user). If it's not visible to the user, it makes absolutely no sense to keep it around when running out of memory. If you're storing [important] data in these views, you're doing it wrong. Data model should be kept in controllers.
When the memory gets low, all the view controllers get their delegate method: didReceiveMemoryWarning called.
The default implementation of UIViewController is to unload the view.
So, all you need to do in order to override this behavior is override the method:
- (void)didReceiveMemoryWarning
{
//[super didReceiveMemoryWarning]; - calling this will unload the view
// Relinquish ownership any cached data, images, etc that aren't in use.
}
I'm using a lot of small images that are placed into UIImageView objects. Currently, I'm trying to foresee the problems that might occur later, such as memory warnings, staying in background and etc. My app is quite small - less than 10Mb but still, I'm a little bit concerned. The reason is that I'm not sure how my app will cope with the situation when a lot of UIImageViews are loaded on screen, then app goes to background, and then after a long time comes back. Do I have to reload all on-screen UIImageViews?
I have read that iOS will cope with UIKit data (such as image views) itself when backgrounded. And that I do not need to worry about restoring this though. It would be OK if my UIImageView objects would use PNG image files directly from app directory. But the thing is I'm using spritesheets (files with several images packed inside), then pulling those images with CGImageCreateWithImageInRect, and then passing to UIImageView at some time point. Now, I'm questioning myself, will iOS cache my on-screen UIImageView objects, or do I have manually to reload those UIImageViews when app goes active? I understand that if a lot of apps will be running in background then my backgrounded app might be killed. But I'm worried about the situation when my app will be still alive (in background) but with released UIImageView objects...Please share you knowledge and insights :)
Current implementation of "background" apps do a complete snapshot of your app memory. Such approach guarantees that app will be restored after complete killing from a memory in unchanged state. This mean that you do not need to do any additional manipulations such as persisting of code-generated images etc to support restoring of the app. UIImageView will not be unloaded automagically if you will not implement a clean-up logic inside of applicationDidReceiveMemoryWarning for UIApplicationDelegate instance. However an auto clean-up logic implemented for cached UIImages loaded thru imageNamed method.
i've a navigation controller with several viewController and tableViewController.
I'm using all autorelease objects, the problem is that when i push a new view and i use it, memory from Instrumets increase of a bigger value of memory released when i come back in the navigationController. There's not leak warning, when i return to the view then, memory will not increase again, it's like if was all in cache.
I've tried also using objects own by me, with alloc....and release but the story is the same. Is it normal?
UIViewControllers (or to be exact, views/resources/xibs associated with them) are interesting since iOS will hold on to the resources in memory and unload them as required. This is why often the dealloc method will seem like it's never called. However don't worry, if you did proper memory management, your controllers and resources will be freed up as required - if there's a low memory warning sent to your app, all the views that are hidden or have been popped, will be unloaded and dealloc'ed.
Try testing your app again, just like you did before, but this time emulate low memory usage (can be done in simulator from the Hardware menu), then see if memory usage drops due to your controllers being freed up by the system
This is a multiple part question, mostly because my ignorance on the matter has multiple layers.
First, I put together a caching system for caching CGImageRef objects. I keep it at the CGImageRef level (rather than UIImage) as I am loading images in background threads. When an image is loaded I put it into a NSMutableDictionary. I had to do a bit of arm twisting to get CGImageRef's into the array:
//Bunch of stuff drawing into a context
CGImageRef imageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
[(id)imageRef autorelease];
[self.cache setObject:(id)imageRef forKey:#"SomeKey"];
So, as you can see, I'm trying to treat the Image Ref as an NSObject, setting it to autorelease then placing it in the dictionary. My expectation is this will allow the image to be cleaned up after being removed from the dictionary. Now, I am beginning to have my doubts.
My application clears the cache array when the user "restarts" to play with different images. Running the application in Instruments shows that the memory is not dropping back to the "start" level on restart, but instead remains steady. My gut tells me that when the array has all objects removed the CGImageRef is not being cleared.
However, I'm unable to confirm this as I don't quite know how to track down the actual source of the memory in instruments. It's just a list of (Malloc 16 Bytes, Malloc 32 Bytes, etc), drilling into them just show a list of dyld callers. Not sure how to properly read it.
So, first question, is my way of caching CGImageRef objects completely flawed? And is there a better way to confirm such things in instruments?
First of all, caching CGImages is OK and I don't see any problems with the code you posted.
Am I correctly assuming you use an NSMutableDictionary as the cache? If so, you can clear it by sending it -removeAllObjects, which should release all the keys and values. If you just set different images for the same keys, memory usage may remain roughly the same because you replace previous images with new ones. If the images have the same size, memory usage should be constant except brief spikes when you create a new batch of images.
As for Instruments, I've seen it both report false positives and miss real leaks. Try running it several times, making pauses, if possible, for the Leaks instrument to "catch up". This sounds crazy, but I think it may make it a bit more reliable.
If all else fails, you can log the contents of the cache before and after loading a set of images to make sure the cache itself works as expected.
Why not just cache UIImage objects; you can make them fine on a background thread?
It's UIImageView objects that you have to be more careful with and even they are OK for most operations in the background.