Memory consumption of images in iOS Web Application - ios

I have a iPad (magazine) web application which displays a set of medium sized (~500kb) images. They're displayed one per view (1024x768), and when swiped another one is displayed.
I have three images (previous, current and next) as display:block at the same time while other images are hidden with display:none.
Everything works fine on some extent. However, when application has run for some time and larger set (20+) of images has been displayed, the application crashes, mostly on iPad 1. My assumption is this has something to do with memory consumption of device.
My question is: what are the best practices to keep the memory consumption as low as possible? Obviously setting images to display:none is not working. Should I remove the images from DOM and then re-apply them when coming into view? Or are the any other simple tricks to prevent application from crashing?

There is an approach where you have to set the source of an image to an empty string before removing the element for the DOM: http://blog.thinkingtype.com/2012/07/ios-mobile-web-application-image-memory.html
So in your case you could store the source in an data attribute of the image element when you set the display to none, and set the source again when you made image visible while setting display to block.

Related

IOS App keeps Images in Memory

I have an app that has two view controllers with images
when I launch the app the memory increases and when I then segue to the other view controller and load the 2nd image ( I have a button to do this ) the memory goes up again.. this is what I would have expected..
However, when I dismiss the 2nd VC controller or removing the image in the 2nd VC via a button, and then dismiss the controller , the memory never goes down.
why is this, with an app with lots of images it could get large.. how do I release the memory of the 2nd VC or at least the memory of the 2nd image.
Im looking at memory under debug navigator in Xcode 8, when running the app.
xcode project can be found here , very simple
iOS will cache images. The documentation for UIImage(named:) says:
Discussion
This method looks in the system caches for an image object with the specified name and returns the variant of that image that is best suited for the main screen. If a matching image object is not already in the cache, this method locates and loads the image data from disk or from an available asset catalog, and then returns the resulting object.
The system may purge cached image data at any time to free up memory. Purging occurs only for images that are in the cache but are not currently being used...
Special Considerations
If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using
imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.
Note, you don't control when this cache is freed. The OS does that as it sees fit (and generally in response to memory pressure).
Bottom line, we often don't worry about inherent caching by UIImage and simply ensure the app doesn't have its own memory issues, e.g. make sure deinit is getting called and/or use the "Debug Memory Graph" feature in Xcode to watch memory graph. Or if you want, programmatically set the image using UIImage(contentsOfFile:).

Best image caching strategy in iOS

In my app, I have a UITableView which displays fairly large images and loads a moderately designed Xib file to display it in. Each image is around 700KB to 1MB in size. The flow is virtually never ending, it loads more and more as we scroll down. So you can imagine that I am running into memory issues.
I have tried using SDImageCache and NSCache. The former used disk memory for caching images. In both cases, the caches somehow didn't clear images automatically. I had to manually clear them when I got a Received memory warning prompt. And each time I clear these caches, the memory freed seems to be lesser each subsequent time.
Now I confused as to which cache strategy I must use for such a long list of images. Might I be having some leaks somewhere? They certainly didn't show up when I profiled the app.
P.S.: I am loading the images from the web. Just to be clear.
From the docs:
UIImage
+(UIImage *)imageNamed:(NSString *)name
Discussion This method looks in the system caches for an image object
with the specified name and returns that object if it exists. If a
matching image object is not already in the cache, this method loads
the image data from the specified file, caches it, and then returns
the resulting object.
So I guess leaving this to the UIImage class is a good approach.
Hope this helps!
As we implemented it in both Android and iOS: once you can show on the screen only 2-3 images.
Load in memory 2 more for the downwards scroll and 2 more for the upwards one. So you have in memory 7 images. Display them. The other images must be stored in files (when you download them). If the user scrolls too fast, do not show all the sequence of the images, instead show some "loading" icons in place of the images. When the scrolling stops, show the appropriate image + the previous one + the next one + prepare 2 more (for upwards scroll) and 2 more for downwards scroll.

Real Memory Constantly Increasing - Removing Subviews from View - iOS (ARC)

I have an iPad app which is crashing on iPad (First model) as it is running out of memory.
In the app I have a main view which adds as subviews about 20 UIScrollViews (custom class) each containing a UIImageView and UIImage. When the user moves to the next page, I remove all these subviews from the superview and then add 20 new UIScrollViews to the same view.
If I profile the app for allocations and memory leaks everything is ok - the memory allocated stays at about 2MB while the user scrolls left and right.
However if I look at the real memory usage in the Activity Monitor I can see that every time the user moves to a new page, the real memory increases by about 20MB. Eventually after a few new pages the app size hits 150+ MB and crashes.
Can anyone suggest what might cause this type of behaviour and how I can further troubleshoot this ?
Just a bit more info on the app structure :
In view did load the images are loaded into an NSMutableArray using initWithContentsOfFile.
You should not be maintaining these images in an array. Images consume a disproportionate amount of your limited RAM. There are a couple of approaches:
If you want to keep it simple, just don't store the images anywhere. Load the image property of the UIImageView by loading the image via initWithContentsOfFile and call it a day.
If you want some RAM caching for performance reasons, you could use imageNamed instead of initWithContentsOfFile. When the app receives a memory warning, the cache will automatically be purged.
I'd be inclined to use initWithContentsOfFile, but then manually cache in my own NSCache (which is like a NSDictionary, except you can set a countLimit of how many images it should hang on to).
By the way, you don't describe what technically happens when "the user moves to the next page." If you're simply refreshing the existing controls on the existing view controller, then everything is probably fine (once you fix the NSMutableArray problem I discuss above). If you're pushing/presenting to another view controller or scrolling controls off screen but neglecting to remove the old ones from their superview, then that will also cause problems. You might want to clarify what you're doing there.
Bottom line, you just need to make sure that when you go from one page to another, that you're not maintaining strong references to any old images or controls.

How to reorganize iOS project to avoid memory issues

I am building my first project that is an interactive ebook app for the iPad
I started with the Single View App template from XCode
So far, the project is mostly a series of block animated transitions between UIImageViews and MPMovieController videos, very serial so far
Everything is coded within a single view under a single view - the image views fade in and out with alpha animations
I am beginning to run into memory issues. I've used memory instruments and see that most everything is loaded into memory at the beginning (images from the InterfaceBuilder) aside from some videos instantiated at runtime
My question is - how should I reorganize my code to better utilize memory? Should I separate into different views under one view controller, or have multiple view controllers?
And which might be the most straight forward to implement?
Images are very memory-intensive. So:
Do not load an image until you actually need it (for display). When you are done with it (the image view is no longer visible), release it (by setting that image view's image to nil). Do not maintain the images in an array or anything like that. Do not create the image views preloaded with images in advance in the nib.
When you actually need an image for display, load it in code using imageWithContentsOfFile:, not imageNamed:. Thus you prevent caching of the image.
It is a waste of memory to work with an image larger than the display size. If these images are large, you can save a lot of memory up front if you load the image at the actual size needed for display. This is easy to do with Image IO framework and CGImageSourceCreateThumbnailAtIndex.
I think you need to use multiple view controllers and separate your code in small separated views and objescts that controll you app flow..
On the one hand it's better to have multiple views and so on..but it's a pain to rewrite code you worked on (unless it's absolutely necessary).
In my opinion if you don't have anything unnecessary in memory (i.e. when you take a view off screen you release the memory it used) you don't need to do anything.
After all, even if you split the code as it should have been, if your memory management is good, it will take the exact same memory.
You should be able to do this with a single view controller:
Load your images lazily from code. Keep an array of the image names rather than the images themselves, and load them just before you need them.
Make sure your images aren't larger than they need to be.
Recycle your image views. If the user won't see more than two image views at a time (including both the from and to in a transition), you should only have two image views.
Don't worry about whether the images are cached; iOS's caches are designed to release their contents under stress. That said, do not implement your own caching system. You might not release images properly under stress. If you need caching, use NSCache.

Showing large UIImage causes jittering even though it is already in memory

I have app similar to sample app PhotoScroller, e.g. lot of large images (2048x1536) in scrollview. I am not using tile approach as I don't like that partial load effect. I would like to show whole image at once. I am loading images in background thread. When I try to use loaded image in UIImageView for the first time, it blocks main thread for half a second even tho it is already in memory.
I used profiler to see where this lag is coming from but I couldn't find any useful information there.
Is iOS copying image data when it is used for the first time or something like that? Can I somehow do that in background thread as well?
EDIT: when I scroll there and back again and use that same UIImage second time, there is no delay
Try to make image in background thread too.
Do you loading image from inet or locally? bundle or custom path?
I think I solved it. Turns out when ios loads UIImage from disc or web, it doesn't load it in correct format. So when you want to display it, ios has to reformat this image into the format that he can use. This reformating can cause visible stuttering when image is big enough.
To prevent this, you need to reformat UIImage after it was loaded and you can do that safely in background (as far as I know). This link show how to do it.

Resources