Is there any way to check smooth scroll in UITests - ios

I created an UI test that load thousands of entries in a tableview. I use the next code to scroll the table view:
let table = app.tables.element
table.swipeUp()
table.swipeUp()
table.swipeUp()
Is there any way to check if the scoll is smooth?

There is no way to test if scrolling of a table view is smooth with a UITest.
XCTest offers performance tests but they are meant for UnitTests only. You can test how performant your code is but not your UI.
You can use Instruments to monitor the frame rate in you app. Launch the app with Instruments and scroll your table view. If the frame rate drops significantly you have a performance bottleneck.
BTW the scrolling performance of a UITableView should not be different for 10 cells or 10000 cells, because the cells are reused.

Related

How to have a reusable scroll like UITableView or UICollectionView in SwiftUI that support all scroll APIs and also indexPathForItem(at:)?

My Goal:
I want to have a reusable scroll like UiTableview in SwiftUI to load views that are not in the same Height sizes also want to control the scroll. Something like Instagram Explore view. Basically, the data source will grow as user scroll more. So I can benefit from the following:
Item Reusability
Scroll To a point
Get the index or id of an item at CGPoint
ScrollToItem
Creating snapping to a point based on Drags and Deceleration
Memory-optimized
My minimum target for this project is iOS 15.
ScrollView:
I tried ScrollView with ScrollViewReader, but even if I use the LazyVStack it will not perform well in case of memory,LazyVStack will create a view when it is needed but after that, it will stay in memory. Also, I can not scroll to a CGPoint, just to the predefined Id.
I can not use .content.offset because then the ScrollViewReader stops working. Also, by using .content, the ScrolView loads all the data at once in memory. I can not get the benefits of controlling its offset.
ScrollView with lazyVGrid doesn't perform well when I want to control the scrollView; it causes so many jumps and unwanted lags and also the same issue that I can not control so much on Scroll and drags. apple suggests this combination for loading a long list, but again you can not control it because it is based on ScrollView.
Adding Drag gesture as .simultaneousGesture to scrollView to get drags is only possible if I set the minimumDistance = 0.0, which means ScrollView will not scroll anymore. so I can not have the combination of scroll and accessing the velocity of user drags.
List:
The list is good in memory and reusability, although you will have the same issues regarding the scroll. But it has another big disadvantage. ScrollViewReader is not well supported for List. it causes crashes in the app., there are a lot of threads in apple forums and StackOverflow that mention this problem.
StackOverFlow thread. apple thread.
I have been working to solve this issue for 2 weeks, but all of them lead me to the point that SwiftUi is not powerful enough for large projects to create an enterprise app that works smoothly and reliably.
So is there any good solution to using SwiftUI for these problems?

App freezes while trying to scroll to bottom ios tableview

I need to scroll to bottom in tableview with many rows without freeze.
I have talbeview with infinity scroll (when user scrolls down, app makes request and fetches new part of data). When i'm trying to scroll to bottom by settig table's content offset or by scrollToRow, app freezes and i see cpu usage 100%, and ram up to 100mb (in normal state it is only 10mb).
I guess this is because of cell rendering. I was trying to set async rendering, or rendering with queue, but nothing.
This problem is seems like Scrolling bottom in tableview and performance but there is no answer.

Loading multiple cells from XIBs in UICollectionView makes scrolling laggy on the first load

I have a collection view with like 7-8 different cells. Cells are constructed in XIB files. Then in View Controller I use:
[self.collectionView registerNib:[UINib nibWithNibName:name bundle:nil] forCellWithReuseIdentifier:name];
Everything works as expected, but there are some performance issues. On the first scroll collection view noticeably lags as cells appear. After all kind of cells have been loaded at least once everything starts to scroll smoothly. Cells are not really complicated.
Q: Why do you even use XIBs for that, why not prototype cells in a storyboard?
A: Same cells are used in different collection views throughout the app. This way I can apply changes to a cell once in a xib. I couldn't come up with easier solution to do that.
I'm pretty sure UINib is cached after it's loaded and this is why it stops lagging. I was wondering if there's a way to preload those xibs at the splash screen for example. It will take a second or two, but will result in smoother experience.
UINib are cached once loaded, there are plenty of reason that could make scrolling laggy:
Are you doing some complex layout calculation?
Are you setting in cells huge images or doing intensive task on the main thread to resize them?
Do you have complex transparencies ?
Are you doing something that requires off-screen rendering, for instance cornerRadius on a layer ?
Using instruments you can really check most of those issues, for instance Time Profiler will help you in checking if something is blocking the UI, using simulator you can activate Color Blended Layer to search for transparencies (in red) and Color Offscreens render to check for offscreen render views (in yellow)

How can you create a zoomable timeline in iOS?

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.

Scrolling UITableView slow

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.

Resources