Reduce Choppy Scrolling in Objective-C - iphone

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.

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.

What's a good general approach for apps like pulse, youtube, NYTimes, etc? Use UIWebView or something else?

That may seem like a broad question, but I'm talking specifically here about apps that display a lot of content (image plus some text) pulled from the net in separate cells, rows, etc. And where each of those cells can get loaded asynchronously (independently from all the others).
So for example, for iOS, is it too inefficient to use uiwebview for each of these cells? It seems like this would be a simple approach, but I'm not sure about the performance. "Pulse" has a bunch of cells on the page at one time, and on iPad this could really get to a large number. Is it better to do this using lower level techniques, or is using UIWebView a decent choice?
Update:Clarification-->
Just to clarify, I understand that the typical approach is to use UITableView and then create table cells to hold and show the data (although the "Pulse" UI may be more involved). What I'm getting at here is if those UITableViewCells could hold UIWebViews? So instead of putting a UIImageView and a UITextView in each cell and so forth, if it makes sense to just put UIWebViews there instead, and give them URLs (could pass a param to indicated the row) to load as cellForRowAtIndexPath is called or something.
Well, if you talk about the YouTube app, its not UIWebview. The common and better approach is to use UITableViews along with the custom UITableCells. As far as asynchronous loading of images is the concern, we implement "Lazy Loading" mechanism. And in this way, we are able to keep the performance benefit of native UIView intact. Whereas, in UIWebView, you would need to design the iphone based webpages which will cost you learn about Dashcode tool, or may be someother opensource css library, etc.
In short, UITableView, with Custom UITableCells, along with Lazy Loading Mechanism (achieved by some Threading Techniques) will do all the Magic for you.
Hope this answer will give you some better idea....
Do not use UIWebViews with UITableViews like that. There are far too many moving parts for a UITableView!
I wrote the NYTimes iPhone app while I worked there. I only ever used a UIwebView to display article content. This is because NYT articles and log post layout is extremely complicated and impracticle to replicate programmatically. (I did override some of the CSS in app)
The UITableView is a super high performance implementation for butter smooth high speed scrolling. UIWebViews are the opposite of that: heavy, slow and memory intensive. In fact web views actually run internal virtual machines and threads (for JavaScript, rendering, etc).
Keep in mind that table view cells are recycled very aggressively. The instant a cell scrolls off screen bottom it will, in gneral, be immediately reconfigured for use as the new cell that scrolls in from the top.
With a UITableView, you need to create VERY highly optimized custom UITableViewCells. The data displayed in the cells should be cached aggressively by you so that you don't need to recompute it or perform intensive layout calculations. Uncacheable information such as remote images should be loaded asynchronously (which might mean they show up much later).
On caching:
The NYT apps have a high performance caching system for images. The trick is to request the imge data as soon as its "needed", but to also preempt downloading images which were needed a second ago, but no longer. You also don't want to cancel partially downloaded images because that wastes the already consumed bandwidth. Check out NSOperationQueue. It has most of the levers needed to build such a system.
Another note: consider building a web app if your project may also be accessed via web or an android app.

Improve UITableView scrolling performance while loading images

I have a scrolling grid of photos that looks and functions pretty much exactly like the photo picker on the iPhone. It is constructed from a UITableView that uses a custom UITableViewCell which displays a row of photos (very similar to how Three20 implements it).
It works great except that scrolling performance is poor. I'm already following most of the best practices for fast UITableView scrolling (à la Tweetie).
The images are all bundled with the app. I load them on the UI thread, on demand. I use UIImage's imageNamed: so that the images will be cached after they're first loaded. Once I've scrolled through the table view once, it scrolls very smoothly.
The problem is, the first time scrolling through the table view, scrolling is jittery. I've profiled the app and found that the majority of the time is spent loading the images from the file system. They are JPEG images, already sized correctly (small). I tried using PNG images instead, but performance doesn't improve very much.
The iPhone photo picker exhibits much better loading performance. I'm wondering if combining all the photos into a single image, which I load once and then split into smaller images would be faster. It certainly works in games, but I know that's really a totally different story. Has anyone had experience doing that?
Any other ideas for how I can improve performance?
Incidentally, I'm having a similar, albeit less, performance problem for another UITableView that just uses standard UITableViewCells with one image assigned to the imageView per row.
One thing to try could be pre-caching all the images when the view loads. Beyond that, perhaps loading the images in the background (even though it's loading from the filesystem and not the web). I haven't tried this myself, but perhaps you could use something like https://github.com/rs/SDWebImage and have the URLs point to the filesystem. Users might see some placeholder images at first, but then the UI wouldn't stutter while images are loading.
Setting the PagingEnabled property to off improves the scrolling performance.
I had a similar issue using a UITableView to display information parsed from an RSS Feed. I ran into scrolling performance issues when there was a significant amount of data. Though I'm still working on it I suspend the parsing when the table is being scrolled. It resumes when scrolling stops. I am not at my computer, but I believe I used tableViewDidScroll and tableViewDidEndDecelerating. You can check these tableview delegates. In any case it works very well, I just need a more elegant way to pause my parsing.
Fantastic. That does work like a charm! So efficiently I ended up using insertRowAtIndexPath rather that reloading the table. Now it behaves the way it
Thanks so much!
Joe

Bubble Chat + Emoticon + UITableViewCell

This is a question for iPhone development and I'm hopin someone can point me to the right direction on how i should go about implementing this.
I am trying to write a chat application that supports emoticons/smileys. Where the smiley/emoticon images are stored can be figured out later. I think few iphone applications out there are already doing this (i.e. skype + ebuddy(?)) but not sure what method they went for.
After searching around, there seems to be a few ways of doing this (i think):
bubble chat style which has been discussed before. UITableViewController with custom UITableViewCell. For emoticons, might have to do a whole bunch of calculations to determine where to stick a UIImageView for each emoticon.
Use UIWebView as the whole "window". Style it to look like bubble chat. Takes away any manual calculations on image smiley placements.
I have no idea what the performance is like for each of these two methods, how complex it can get etc, so any comments and guidance will help for sure. Cheers
If you use custom UITableViewCell, then I'd probably implement drawRect: instead of adding labels and images. One will probably take as long to implement as the other, but it will perform much better.
The UIWebView might be worth a short, although you will have to make sure that everything looks right there, too. Instead of using one big web page, I suggest simply throwing in a web view into each table view cell.
Personally I prefer the first approach, measuring and layout of text is not too complicated, but then I've never been the ultimate HTML guru.
I agree with #Eiko on making custom UITableViewCells, especially using drawRect instead of adding labels, images, etc.
If you used a UIWebView how would you handle updating it? A complete reload each time new text is sent? That seems like it will be a cause of issues. Once you get a long conversation reloading the entire UIWebView's contents will cause some flickering which isn't acceptable in my opinion. Also using a UIWebView would require you to have 2 complete copies of each conversation in memory. 1 as your backend data and 1 as the HTML. Where using a UITableView you have your backend data, and only enough of that will be duplicated that can fill 1 screen at a time.

Using CGLayer to Cache Cells in a UITableView

I am trying to improve the performance of scrolling in our app. I have followed all of the generally accepted advice (draw it yourself with CG, the cell is opaque, no subviews, etc.) but it still stutters sometimes when we have background CPU and network activity.
One solution stated here:
http://www.fieryrobot.com/blog/2008/10/08/more-glassy-scrolling-with-uitableview/
is to cache bitmap snapshots of the cells, which we tried. But the bitmaps were fuzzy and took up a ton of memory (~a few hundred kb each).
One suggestion in the comments of that link is to cache the cells using CGLayer or CALayer(?) because they go to the graphic card's memory. So a few questions,
1) Has any tried this? Sample code?
2) How much memory does the iphone/ipod touch graphics card have? Does this make any sense?
3) Any other suggestions for speeding things up?
More information
I used the CPU sampler (on the phone) and systematically eliminated things from the cell to figure out the problem. A few things:
1) It isn't the setup of the cell. If I remove just the drawing calls (drawinrect etc), but leave the setup, it is glassy.
2) It isn't the drawing of the smallest image (25x25 png), if I put that in it is fine.
3) If I add the second or third image (the first is a big background 320x1004kB, the other is a button image 61x35 4kB) it stutters. I am grabbing both UIImages in a class method, so it is cached.
4) The text is also a problem. It looks like by drawRect spends 75% of its time in the three NSString drawInRect methods I am using. Like:
[mytext drawInRect:drawrect withFont:myFont lineBreakMode:UILineBreakModeTailTruncation];
Those calls seem to go through webcore, perhaps that causes some of the stutters? I need to be able to format two lines of text, and one small paragraph of text. I need the ability to truncate the text with ellipses. Can I perform these out of the critical path and cache them? May I can do that part with a layer?
CGLayers are not cached on the GPU, they are used during the process of drawing Core Graphics elements to a context. CALayers do have their visual contents cached on the GPU. This can "hide" some of your memory usage, but you're still going to run into memory problems if you hold on to a lot of CALayers.
Honestly, if you've followed the table view best practices, as described by Loren Brichter and others, of drawing all of your content via Core Graphics in one layer, making your cell opaque, and obeying the cell reuse mechanism of the table view, there isn't much more you can do. Overloading the CPU on the iPhone will cause stuttering of your scrolling, no matter how optimized you can make it. The inertial scrolling animation does require some CPU power to run.
One last thing to make sure of is that the background CPU and network processes you refer to really are running on a background thread. Anything running in the main thread will cause your interaction methods to pause while that task is processing, potentially adding to the choppiness of your scrolling.
Before you go too deep into the optimisation, are you using the cell reuse mechanism ([tableView dequeueReusableCellWithIdentifier:]) for creating UITableViewCells in your delegate's tableView:cellForRowAtIndexPath: ?
Also, have you run the code in the Simulator using Instruments' Activity Monitor? Set the interval to 1 ms (I found the default - 10 ms - too big for this) and see where most of your time is spent when doing the scrolling.