UICollectionview poor scrolling with CALayer and CATextlayer - iphone

i have a collection view with lets say around 50 objects, each object has one of three images based on its category (never mind it), also each object (that becomes a cell) has two CATextLayer objects and a logo (each cell has a unique logo).
i have created a reusable cell that contains all of the above parameters - the category image is assigned to the cell contentView.layer, the logo is a calayer (which i create when the cell is first created and then just change it value - rather than adding a calayer each time cellforitematindexpath is called) and by the same technique change the catextlayer which differs from cell to cell (based on the datasource object info).
everything works well but the scrolling is very slow on an iPhone 4, i guess thats because that for every cell that gets called i go fetch the logo (which is on a directory). the category based images are instantiated as a layer when view load (so i don't need to fetch them when a cell is called) - thats faster but what can i do with the logos ? i cannot initialize 50 images and have them eat all of my memory.
i have a solution that can cause fast smooth scrolling - initialize the first objects that the user sees in the collection view, and load the cell parameters only when there is no dragging or decelerating - and than use uicollectionview.visiblecells to which cells i need to load.
but i don't want that - i want the user to scroll and see all of the cell parameters
instead of a activityIndicator.
do u have some other approach to this?
btw
i used to use UIKIt for all of that but i moved into Core Animation because i got the impression it will be faster.
tnx.

See WWDC 2012 videos iOS App Performance: Responsiveness and iOS App Performance: Graphics and Animations for some tutorials on how to use Instruments to identify the problem.
If you haven't done so already, I'd move to making the image retrieval process asynchronous. Also, if your images are large/i.e. being resized, you might want to save/use the resized/thumbnail rendition, which can improve performance. That former video even talks about the idea of replacing a complicated set of labels on a busy UICollectionView with image snapshots.
But, as David said, until you run it through time profiler, we're just guessing. To paraphrase the workflow Apple uses in those WWDC videos, you have to use instruments to quantify/identify the precise problem, form a hypothesis, quickly test that hypothesis before investing too much time in the solution, and if the hypothesis stands up to scrutiny, only then dive into implementing solutions.

There is one library to load images in the back ground. it follows the concept of lazy loading. if you use that your app scrolls smoothly.
In the following library there is "EGOImageView". use this class in place of ImageView and set the image paths to "ImageURL" property
EGOImageLoading
incase if you won't find EGOCache files in that, then download those from the following link
EGOCache
Regards,
Satya

Related

Optimizing Performance on iPhone

I released the first beta version of my iPhone app on TestFlightApp today. Everything is going really well until I notice that the responsiveness of the application is pretty cruddy. Certainly doesn't have a "nice" native feel that I'm going for.
I've been particularly fastidious concerning my memory allocation/deallocation, so I don't think this is the issue. Basically, I don't know where to turn to next in order to improve the performance of my app.
Here's where I think some of my slowdown can be attributed to:
Using UIAppearance to customize the looks of most (if not all) UI elements. I use a brand new font, lots of CAGradientLayers, and lots of edits to CALayer in order to draw nice Shadows.
Grouped UITableViewCells that display pictures of a map and itemized lists.
UITableViewCells whose layouts are updated every time I call layoutSubviews.
UITableViewCells with customized heights. For each call of heightForRowAtIndexPath, I need to reconstruct and re-layout the view, returning the exact height each time.
Because I programmatically created views, controllers with longer viewDidLoad calls tend to load slower. What code can I offset in the init call?
Does anyone have any hints or tips for dealing with these problems? Or perhaps people have stories about how they dealt with a slowdown in performance when they released their first app?
My answer won't address all of your points, but here are a couple:
1) Make sure you are using Shadow Paths. Paths are much, much more performant.
2) Are you using transparency or corner rounding? If so, try and reduce transparency as much as possible and do not round corners using CALayer cornerRadius. Instead, use a clipping mask in the drawRect of the view that needs to be rounded.
4) Perhaps you can cache the height in an array and not have to repeat the calculation, each and every time. This may/may not scale well depending on the potential number of items, but may be acceptable depending on the use case.
5) Are there views you can reuse? For example, when I have a custom selection view on a UITableViewCell, I only create a single instance held by the controller and reference it in all the cells.
Did you run Instruments (or other profiling methodology) to determine where you app is spending most of it's time. It would be a good idea to do this before optimizing the wrong thing.

ScrollView as PhotoViewer, load Images only if needed

I would like to create a PhotoViewer for an iPhone.
For that, I already created a ScrollView with Paging enabled in that I add programmically add the UIImageViews. The problem I see is, that if I would have like 100 Images and I would all add to the ScrollView it would take alot of performance and memory.
How would you make it more performant? I thought about loading the Images of the following 2 pages and releasing the Images after the 2 Images before when scrolling through the pages.
I thought about creating a Subclass of UIScrollView and to name it UIPhotoScroller (or something like that). But I also want to show a UIView in the MainWindow with Information about the Images. Is it possible to make the UIView visible from the Subclass?
You really would help me with that. Thank you in advance :D
Create an NSCache.
When you need a particular image, try to get it from the cache. If it's not there, load it from disk and save it in the cache. The filename is a suitable key.
When you get a memory warning, tell the cache to empty itself.
The cache will release some of its entries periodically, depending on how it's configured. This is a good thing, but you might want to adjust it to have a particular total memory size. Tweak its parameters until it behaves like you want it to. To see your memory usage, use Instruments.
How about doing a UITableView with a single photo per cell. When a cell is being request by the data source, you display a spinner and have a queued NSOperation load the image and refresh the row when done.
You can control the amount of concurrent ops with a NSQueue, so you have complete control on performace/responsiveness. You can then remove old cached images when low on memory/paging, etc.
There are solutions to horizontal UITableView if you need horizontal scrolling.
Have you looked at the three20 library? There's an example of creating a great Photos app-like viewer of photos, and it's pretty easy to work with the three20 library.
Hope this helps!

iPhone memory management, making my app crashproof for multiple devices

I'm developing an app which uses a UIScrollView to show a list of images based on search criteria. Using a button the user can load more images.
When testing on an iPhone 4 the ViewController receives a memory-warning at ~750 images. When testing on an iPod 2nd generation a memory warning is received at ~150 images.
My understanding is that when didReceiveMemoryWarning is called, one can free memory by releasing objects but recovery from low memory is not guaranteed.
I've implemented didReceiveMemoryWarning and release basically all objects. In instruments I see memory usage drop back to ~3MB. The first time the iPod reaches its memory limit all goes well, memory is released and the app resumes normal operation. The second time however, when didReceiveMemoryWarning is called, I can see the objects released, but the app crashes anyway.
So, how do I make my app crash proof? I want to make sure that all devices running the app can load as much images as memory allows but I also want to make sure that the app doesn't crash.
I would prefer the app never to reach didReceiveMemoryWarning and set a limit to the number of images that can be displayed, but how can I determine how many images each possible device should be able to load?
Furthermore, the size of the images is not guaranteed. While testing I come to this arbitrary number of 150 on an iPod, but what if the images on the server at some point in time are twice as big? Then the app would probably crash at 75 images.
Any sugestions?
First off, what you probably want to do is not display all your images all at once. You rather, probably only want to disable the images that are currently visible, plus a few that are off screen preloaded for when the user scrolls to that location.
This is much the same way as the photos app works, how UITableView is implemented. Basically it boils down to this:
You have your main scrollview, and inside it, you have individual cells. These cells are small views that are added as subviews to your scrollview at specific offsets. You then add your images to these cells.
When a user scrolls the scrollview, you first ask the scrollview to dequeue a new cell for you, much the same way you'd ask a table view to dequeue a cell for you to use. This saves the cost of an allocation, if one has been recycled. If you cannot dequeue one from a recycled set, then what you have to do is quite simple: allocate one as you are doing currently.
Furthermore, to implement this cell recycling, what you need to do is see which cells are visible on screen. If one or more cells go off screen, you add them to the recycled cells NSSet which you create. This set just holds cells for later recycling. There's some sample code Apple has which demonstrates this, and it's called PhotoScroller. It also is demonstrated in a WWDC10 video, session 104. I suggest you watch it. Ignore the parts about tiling, you don't need to know that for your purpose.
Once you have this in place, this will force you to set up your cells only when they're needed, which is also another key aspect of this behaviour.
Finally, when you do receive a memory warning, just drop the recycled cells set. If you ever get high enough that this matters, that is, you'll save a few megs of memory. :) (Do not forget to implement it though, ever, when you hold onto temporary data that you don't specifically need around...cells which are not visible on the screen are a good example of this, as are caches.)
You should lazy load your images and only load the images you need at that time. Your app can't show all those images on one screen anyways, so on your scrollview you should only load those images that can fit on the screen and maybe a few around that, and as the user scrolls to release the images it no longer needs.

Reduce Choppy Scrolling in Objective-C

I know this is kind of a vague question, but does anyone know how to get rid of choppy scrolling on a tableview?
Thanks
I suggest reading up on the subject but a few main things are:
Don't do heavy calculations in your GetCell function (it is calculated several times per second as each row appears.
Make sure as many elements in the cell are "opaque" as possible. Read about red/green transparency checking with instruments / simulator. Transparent areas require compositing which causes a performance hit with the hardware (especially on iPhone/3G).
Make sure you are using a constant cell identifier so dequeueReusableCellWithIdentifier isn't creating a new cell every time one is needed.
Have you tried Apple's suggestions for Cells and Table-View Performance yet?
You might also want to look at the TableViewSuite sample code for different techniques for creating fast scrolling table views.
Try Atebit's fast scrolling table cells:
http://news.atebits.com/post/197580827/fast-scrolling-in-tweetie-with-uitableview
The idea is that instead of a deep hierarchy of subviews you draw everything flat to the content view so that rendering doesn't have to composite lots of transparency.
Another possible problem may be background web calls - if you are using asynchronous calls to servers, try moving them into background threads. That can really improve UI performance.

How to load images from server to tableView efficiently?

I have a table view with all cells having the UITableViewCellStyleSubtitle,
the images of all the cells are got from the server.
However, those images are not changed frequently.
Someone can show me how to improve the user experience? Each time, user scroll down the table, it seems that it goes online to check and download images again.
Or at least, show me some options that are available to achieve the goal.
Thanks,
The Three20 library has an ImageView subclass that accepts a URL to your remote image and uses the excellent TTURLRequest/Caching mechanism to fetch images. It maintains an in-memory and on-disk cache and will only download images if they are not cached or have expired. You can configure the default cache-expiration time or use a value from your HTTP response. If you use the TTTableViewController subclass and the appropriate TTTableItem subclass, you will get the appropriate image downloading behavior for free. However, it is not necessary to use every three component to do what you need. If you're integrating into existing code, you could create your own UITableViewCell subclass that uses a TTImageView instead of the standard UIImageView. Then, in your cell configuration methods, you can set a default placeholder image and a URL to load and it will pretty much take care of the rest. As a performance optimization, you should also implement the UIScrollView delegate methods in your tableview controller to suspend the TTURLRequestQueue during scrolling (take a look at the TTTableViewController to see how this is done).
You could try one of the following
Create an dictionary and cache all the fetched images in it using the image name as the key
Cache and reuse the entire UITableView cells in tableView:cellForRowAtIndexPath:
If it is just one image repeating load it one outside tableView:cellForRowAtIndexPath:
You write that the images change on a monthly basis - you could save the images to disk as they are used and just either check if the images have changed on the back burner or at a given daily interval redownload the images. Brian Chapados reply seems interesting .
Depending on your code there is probably a ton of other ways to improve image loading. Hope that helps...