IOS optimalization loading Images into UITableView - ios

Hello I’ve problem with loading images in my UITableViewCells. Ofcourse I use dequeueReusableCellWithIdentifier for my cells. The major problem appears when I scroll table really fast, and cells which displays images freeze app for a 0.1sec but It’s wierd and user unfriendly. Images are cashed in array as UIImage, only what I do with images is setting for UIImageView. Any solutions?

You need to create a scaled-down version of each image to use in your table view. When you display an image on screen for the first time iOS needs to decode that image, which of course will take longer if the image is bigger. This alone can cause a bad scrolling experience. But then for each image on screen the GPU has to read the huge image and scale it down. This also takes a lot of time and produces a lower quality rendering than scaling the image using Core Graphics.

Images with 2000x3000 dimension is really big. Maybe try to crop it using MGImageUtilities(https://github.com/michaelhenry/MGImageUtilities)

Related

Loading large images faster in UIImageView

Is there an accepted way, or updated way, to more quickly load images into a UIImageView?
My scenario: A collection view, with a large UIImageView. Only 1 cell is displayed at a time. I have implemented NSCache and Prefetching on the collection view already. Performance on scrolling has a pause partway through. The images I am using are "relatively" large, in order to accomodate both an iPad and iPhone layout. For example, images are 1600x1600px, RGB, PNG. (from 2-5MB compressed, ~10MB uncompressed, stored locally in the app)
Once the images are loaded, scrolling back and forth is usually OK then, ~60fps visually. But on first load they are ALWAYS jittery. BUT if I make the images physically smaller, such as 800x800 then they load quickly and I can not see a jitter on scroll. So I am dealing with an image size vs drawing speed issue. Same issue seen on a 5s as on an iPhone X.
The same performance hit happens with [UIImage imageNamed:imageName] or [UIImage imageWithContentsOfFile:imagePath]
I am reading how UIImages are decompressed before actually being drawn, and if the system has to draw a subsampled image, it can significantly affect main thread performance. I've done a little Instruments testing and confirmed that it appear that none of my code is actually slow, the image drawing of a PNG is slow.
Is there a newer way to do something similar to the content in links below, IE draw an image in a CGContext and hope it stays cached?
https://www.cocoanetics.com/2011/10/avoiding-image-decompression-sickness/
- (void)decompressImage:(UIImage *)image
{
UIGraphicsBeginImageContext(CGSizeMake(1, 1));
[image drawAtPoint:CGPointZero];
UIGraphicsEndImageContext();
}
https://gist.github.com/steipete/1144242
this seems like real overkill for me:
https://github.com/path/FastImageCache
I have implemented NSCache and Prefetching on the collection view already.
Good, but
(1) you should not NSCache images
(2) you should downsize the image to the max size needed for display
(3) you should not be doing anything time-consuming in itemForRowAt: (you didn't show yours) — you have only a couple of milliseconds to produce the cell and get out
(4) if you can't provide the image in time, provide a placeholder and get out of itemForRowAt:; you can always reload later when you have the real image
(5) do all time-consuming work off the main thread (includes converting to UIImage and drawing UIImage to downsize it)
(6) measure measure measure! this is why we have Instruments; do not guess where the problem is

Does the size of a placeholder image affect performance?

At the moment I am downloading images remotely using a UIImageView category. While the image is downloading I use a placeholder image that is stored in an xcassets folder.
Is it worth having multiple placeholder images for different sizes: small, medium, and large? Or is it worth having 1 placeholder image and using it throughout the application?
Does the size of a placeholder image affect performance?
Well, you should have #2x and #3x version of the images, as it will mean less work by the CPU to scale up / down the image on different devices. Also, there is technically work done by the CPU to scale an image up or down. However, Apple's graphics processor is pretty efficient at scaling images.
So the technical answer is "Yes, it does affect performance", but in reality it is probably not a big enough difference for you to notice.
Now, if you have built a poorly written app that displays hundreds of these placeholders in a UIScrollView instead of some form of a UICollectionView (which only displays what is on screen, or about to be on screen), you will notice that the slight performance difference for all those images adds up to a large performance difference.

iOS app crashes because images use too much ram

I know this is a stupid problem, but this is my first real app that I have to make, I have no one to ask and I looked up this problem and found no other similar problems.
My app crashes on real devices with no exception. I saw in the simulator that uses too much RAM and after a while I got to the conclusion that the pictures I am using are to blame.
The app is structured in this way: it has 8 viewControllers for different things: for example, it starts with one which lets the user select the avatar with which he/she will play and here I have two pictures, next is a viewController which shows the stats for that avatar and here it is another picture and so on. The problem is that each picture uses 40MB of RAM to be displayed and things add up so the app uses more than 300MB of RAM when the user gets to the gameviewCOntroller where the game is. Because of this, on devices like iPAD 2 or iphone 4 it crashes, but not on iphone 5.
I tried to set the images both from "images.xcassets" and from a ".atlas" folder, but the result is exactly the same. The pictures have a dimension of no more than 1500x1999px, they are in png format.
Also, I saw that if the app were to start directly into the gaveViewController it would use 180MB so the other viewController remain in memory or something like that. Should I "clear" them or something similar?
//-------update-------
This is what I got from Instruments:
Memory is a big deal on mobile devices, there is not a clear answer to you question, but I can give you some advices:
If your images are plain colors or have symmetric axes use resizable images. You can just use one line of pixel multiplied by with or height to cover the entire screen using a small amount of memory
Image compression doens't have effects when the image is decompressed. So if you have a png that is 600kb and you are thinking that converting in a 300kb will lower memory usage is only true for "disk space" when an image is decompressed in memory the size is widthXheightXNumber_of_channelXbit_for_channel
resize images: if are loading a 2000px square image into memory and you show it inside an image view of 800 px square, resize before adding it.You will have just a peak while resizing, but later it will use less memory
If you need to use big images, use tiling techniques such as CATiledLayer
If you don't need an image anymore get rid of it. It's ok to have an array of path to images, but not an array of full uncompressed images
Avoid -imageNamed it caches images and even if Apple says that this cache is released under memory pressure, you don't have a lot of control on it and it could be too late to avoid a crash
Those are general advices, it's up to you if they fit your requirements.
You should definitely follow Andrea's advices.
Additionally you should consider setting the image size to exactly what your need is. You're saying that you've tried to set them from xcassets so you have full control over the images you're loading, which is great (compared to downloading an image that you cannot modify).
I highly suggest you read some documentation on using Asset catalog files. This will allow you to have high-resolution image for bigger screens that also have more memory, and smaller ones for older devices, which is what you want here.
Also, note that 1500x1999px is still a very big size for most mobile devices.
More links about screen-size:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html
http://www.paintcodeapp.com/news/iphone-6-screens-demystified

Display large images on iOS without precut tiles

I'm building a camera application that saves the image data to a single JPEG file in the sandbox. The images average at about 2mb in size.
Problem : I cannot display the images in a photo viewer because having a few images in memory throws memory warnings and makes scrolling through the images very slow.
I cannot split the image into tiles and save them to disk because that's even more expensive than displaying the single image. I tried splitting the image up into tiles upon capture, but on the 5S it took, on average, 5 1/2 seconds to save all the tiles to disk. It will only get worse from there as the app is executed on older devices. This is very bad because what if the user exists the app in the middle of the save? I will have missing tiles and no uncompressed original file to find missing tiles later.
Question : what's the best way to show a full sized image without causing memory issues and keeping the scrolling fast? Tons of camera applications on the App Store do this and the Photos app does this, there has to be a good solution.
Note : I'm currently showing a thumbnail of the image and then loading the full size image from disk in another thread. Once the full size image loading has finished, I present the full size image on the main thread. This removes the memory issues because I only have one full size image in memory at once, with two thumbnails, but still causes lagging on the scrollview because drawing the full size image in the main thread is still pretty expensive.
I would greatly appreciate any input!
you could..
create a down sized thumb nail..
create a smaller image and save that in a different "sandbox" folder.. and read that for browsing.. then after that load the image if the user wants to look at it full size.
One way to deal with this is to tile the image.
You can save the large decompressed image to "disk" as a series of tiles, and as the user pans around pull out only the tiles you need to actually display. You only ever need 1 tile in memory at a time because you draw it to the screen, then throw it out and load the next tile. (You'll probably want to cache the visible tiles in memory, but that's an implementation detail. Even having the whole image as tiles may relieve memory pressure as you don't need one large contiguous block.)
This is how applications like Photoshop deal with this situation.
Second way which I suggest you is to
check the example from Apple for processing large images called PhotoScroller. The images have already been tiled. If you need an example of tiling an image in Cocoa check out cimgf.com
Hope this will helps you.

animate images in sequence

I have an array of 24 high quality images. I am trying to animate them using uiimageView.animationImages property. But the app is crashing whenever I try to run this animation. I have searched a lot on this and found that the crashing is due to the number of high resolution images I am trying to animate. But I am not able find any alternative for this. I tried using animated gif images but the quality is too bad. Please help.
You could try to create your own UIImageView class with an NSArray of all images. Load all UIImages, start a NSTimer and cycle through all UIImages. This might not be the most efficient way but it shouldn't crash.
Although the images are high resolution and big, your screen size is small. So I would say scale down the images to you max screen size and then try using animationImage property of UIImageView.
That way you save on memory and load time.

Resources