I want to see the UITableView sliding performance, like scroll velocity, memory occupy etc. Can Xcode Profiler do this? Give some numbers or graphics?
I am having a problem with UITableView, that has a UIImageView as a subview of UITableViewCell. When I set it's layer's corner property, the UITableView scroll becomes less smooth.
Yes you can use Instruments to collect the CPU and memory usage. You may refer to this document.
In your particular case, you first collect CPU usage. Then you expand the method named scrollViewDidScroll and cellForRowAtIndexPath, and check if any CPU demanding lines. Typically you have to complete each call within 16ms so as to maintain smooth animation at 60fps.
Related
I have an UIScrollView. My most of the operations are on the zoom level of UIScrollView. I test using instruments, at normal zoom level (i.e 1) its taking less memory but when I zoom its taking too much memory and crashing also.
Detailed scenario:
I took UIView as subview of UIScrollView. I am drawing some shapes on it.
I have to show information in these shapes when the UIScrollView zoomed. So I am adding information view on UIScrollView when zoomed and remove it when zoomed out.
I need to know, whether UIScrollView takes more memory on zoom or my approach is wrong?
UIScrollView itself does not define drawRect: so it takes only small amount memory for storing its properties.
When zooming UIScrollView applies scale transform to the contents view returned from viewForZoomingInScrollView:. This does not change amount of memory consumed by the contents view, just changes its visible rectangle. So if your app crashes when zooming look at the code you execute when/after zooming.
I would like to create a zoomable timeline in my iOS application for a kind of a todo-list. Zooming in would display days and hours and zooming out would trigger the folding out of days or zooming out to months. There would be a scrolling function.
As an example, I would want it to work like this: http://almende.github.com/chap-links-library/js/timeline/doc/
What kind of basic view would be an appropriate starting point for this, keeping in mind that the memory needed should be as low as possible? Would a UITableView, UIScrollView, or something else work for this?
The UICollectionView / UITableView will not work because the cells are almost always the same width/height. Most importantly the cells always have the same spacing in-between each cell. Because of this it is able to easily calculate what the index range is, and query the dataSource for the cell's it needs based on index.
A timeline view on the other hand is much different than these controls. The spacing between cells is different, with the cells sometimes overlapping with each other. If you had a data source sorted by position, the control would still have to guess where to start looking for the range. So finding the correct index range is going to be more expensive - you just have to find the right algoritm to determine this in a shorter amount of time.
You're going to have to build your own control by subclassing a UIScrollView. You shouldn't have to mess with drawRect at all. An important concept, which is used by UITableView and UICollectionView, is dequeue'ing cells. The iOS 5 version of Apple's PhotoScroller demonstrates this concept with paging (the iOS 6 version replaces the custom paging with UIPageViewController). You'll have to download the old documentation to get the old sample code.
I'm currently building a timeline view, which I will open source at some point. It's somewhat based on the UITableView and works in horizontal or vertical direction. It dequeue's cells just like the UITableView. I'm not focusing on labels or scaling, but the concept of having inconsistent spacing in-between cells. To give you a head start, here are my dataSource methods I settled on:
- (NSInteger)numberOfCellsInTimelineView:(TimelineView *)timelineView;
- (CGRect)timelineView:(TimelineView *)timelineView cellFrameForIndex:(NSInteger)index;
- (TimelineViewCell *)timelineView:(TimelineView *)timelineView cellForIndex:(NSInteger)index;
Two of these calls are identical to what UITableView has, but it has a new call called cellFrameForIndex. What's significant about this call is that the TimelineView can guess an index and lookup the frame of the cell and see where it fits in the visible bounds. If it guesses a cell inside the visible bounds, it can simply iterate forward and backward until it finds the edges.
Currently the algoritm I'm using takes round(count * (CGRectGetMidX(timelineView.bounds) / timelineView.contentSize.width)) (for the horizontal direction). Basically what this does is takes the mid-point of the visible bounds of the UIScrollView and gets the percentage of what has been scrolled. Then it multiplies that by the number of cells. This works fairly well. When testing a random data-set with 100,000 records at random spacing the calls to cellFrameForIndex ranged from 8 to 150. I'm able to pull 52-60 FPS with this. I'm still working on it, and trying to find a better/quicker way to determine the index range. I'm trying to keep it down to visible cell count + 10 (max) iterations.
If you have time to wait, I'll update my answer to include a link to my GitHub project when I'm done. This could be a few days, to a week. I may add scaling. But you'll have to fork it and add labels and anything else you want.
Edit:
Here is my Github project: https://github.com/lukescott/TimelineView
UITableView is definitely not suitable. UIScrollView might be better but it is not very well suited for dynamic or very long content.
I believe the easist approach would be to do it everything by yourself - implement it by a UIView subclass with a drawRect. Of course, you should use UIPanRecognizer in the same manner as UIScrollView uses it.
I'm making a music app that displays musical notation. Currently the notation is in a very large view that extends horizontally until the music ends. Obviously this isn't a good solution because I quickly run out of memory when display large scores of music.
My question is how I can implement my view such that the view where I do my drawing is only the size of the screen, but the content gets scrolled across it (The view is contained in a scrollview)? I imagine I could just only draw stuff on the screen and redraw the view as it gets scrolled with different x coordinates, but this seems ugly and would be pretty slow.
Thanks for any suggestions. : )
There are a number of solutions around. Usually these involve drawing one-or-two screen widths past the edges, then scrolling as needed, and drawing again into the area that was previously visible. In essence, using the scroll-view as a circular buffer.
Try a Google search for UIScrollView infinite scroll.
Also, see Infinite horizontal scrolling UIScrollView.
I have a tableView ,each row has four graphs in it with around 20 rows.
As i try to scroll the table i will remove the existing graph and build new graphs for each row.
This operation make the scrolling of the table view very slow.
Any ideas to make the scroll faster as well as load new graphs.
Creating new views is an expensive operation. That's why it's best to reuse them. You can do this by "dequeueing" existing views to recycle.
Also take a look at Table View Programming Guide for iOS
Specifically, look at the section "Subclassing UITableViewCell" that covers optimisation techniques, e.g.
Draw the entire cell only when appropriate. Your subclass of
UITableViewCell could draw all of its content in its drawRect: method,
but you should be aware of the potential drawbacks of this approach.
Custom drawing applies to the cell’s layer, which can be obscured by
any views placed over it. For example, in table views in the grouped
style, the background view (the backgroundView property) obscures any
drawing performed in drawRect:. The blue selection background will
also obscure any drawing. Moreover, custom drawing that occurs during
animation (such as when the table view enters and exits editing mode)
drastically decreases performance.
Slow table scrolling is a common issue, so you'll be able to find plenty of similar questions covered here on Stack Overflow.
The other thing to consider is that your methods for providing data could be the bottleneck. Instruments will be able to help you identify the issues.
I've developing an iPad app.And I have a uitableview, in which every cell has about four to five images.And almost four to five cells on screen.
So there are about 20~30 images on screen.
The images are not very large , perhaps 200*200.(already some kind of thunbnail)
All the images are local resource.
The problem is that when first scroll down the tableview, it needs to load new cells and of course the images in the cells. This makes the UI become laggy.
But when you scroll back up ,it's very smooth. I know this is because UIImage class will cache some images.when scroll back up, the images are cached, so it's smooth.
So my question is how to deal with this?
1.Make as small thumbnail as possible?
2.Pre-load some image?(How?)
3.Use custom cache?(also how?)
I would recommend fetching the images with GCD. I would also subclass the UITableViewCell and in it's drawRect: draw all pictures on the view's layer. That will increase your performance dramatically.
If there is not so much images in the table - you can precache by loading them, when the view is created. Otherwise use more generic approach with async loading in background thread.