When new data is received by my app, a notification is sent out and received by my view controller. The view controller then reloads one of the sections of its tableview. This typically takes just 40ms or so.
However, if I have pushed another view, the notifications are still processed by the original controller but the reload of the tableview takes about 10-20x longer.
I can certainly work on improving my tableview performance, but first I need to understand what is causing this. Would also appreciate some help using Instruments on how to debug this myself. So far I have run the 'Time Profiler' instrument and it looks like most of the effort is expended in system method, '[UIView(Hierarchy) layoutIfNeeded]'. This doesn't mean much to me.
You definitely don't need to be updating UI on an element that isn't onscreen. UI updates will take place in the main thread, which will negatively impact user experience.
Updating your data source (in a background thread) should be more then adequate, and then you can update the tableview when it is next shown to the user.
Related
Currently, I have a UItableview which loads based on API. And when clicking on a cell, it segue(show e.g.push) to another viewcontroller. It displays all the cells after the first API call, then it calls other APIs and loads other data(which takes a while and also uses cpu heavily), but the scrolling seems to be smooth when loading.
However, when not fully loaded, if I click on a cell and the other viewController pops up, the entire app freezes for a moment. (The new viewController has all the content displayed, just not responsive)
Is there a solution for this?
What I can think of right now is to decrease the CPU load by loading fewer cells at a time.
Typically you are not going to want to do this:
"loads other data(which takes a while and also uses cpu heavily)"
The better solution would be to not call your second call to fetch all the data and just fetch the data needed to show on your next view controller you are segueing to. Typically done by passing an ID in your API call. So on your tableviews didSelectRowAt you would make the api call to get your data needed that is specific to the next screen, then segue.
If this is not possible due to server side limitations, then you are going to want to chain your first two calls. Meaning don't even show the table view cells until you have all the data.
I'm creating a project which uses a UICollectionView. As the user selects a cell this slides them to another UICollectionView of similar nature. Ive been noticing that no matter how I go about this I wind up with mountains of memory usage.
I've been experimenting with placing UICollectionView's in full page UICollectionViewCell's so as to take advantage of the reusability of UICollectionViews. The downside of this approach has been memory retention as the CollectionViews are never fully deallocated. Ive also heard that it is not the best practice to put a UICollectionView in a UICollectionView.
I've experimented with UIPageViewController's containing UIViewController's with the UICollectionView inside. This is more efficient as the UIViewController's can be deallocated as the user swipes back however as long as the user continues to select cells and create new view controllers the memory grows unbounded looking like a mountain.
As a bit of a hybrid I attempted as well to put ViewControllers containing UICollectionView's on UICollectionViewCell's. This method seemed to work best but I had to deallocate the view controllers manually as the user swiped.
Are there any strategies or libraries anyone could recommend that would fit this problem. How can I keep the memory down. I understand I'll need some kind of reusable views.
Ive been looking into this Library so far thank you in advance for all of your advise
Parchment Library
I think I understand what you're saying. You have a UICollectionView that can drill down to another UICollectionView, leaving the first one and its backing data retained until you come back and pop it off. Drilling down further and further allocates more and more memory until you back out.
I'd keep things as simple as possible. Solutions like putting a UICollectionView inside UICollectionViewCells can cause your code to get unnecessarily complicated, resulting in new issues and code that's programmer-hostile. If the user experience that works best is a collection view UI that you can drill down into infinitely, then go with that paradigm.
Your issue is not with UICollectionViews, it's in managing your backing data's memory use. That could be done a few ways. It would help to know what kind of data you have that's so large, and what "large" means, but here are a few approaches that come to mind.
One idea would be to unload any large data when you go to the next screen. For example, if your datasource uses an array with a bunch of large images, clear them out when the next view is pushed. Reload the data when your view appears again, or do it lazily when the view's cells need it, whichever works best for you. This would be the easiest approach and probably take care of your memory concerns.
A second approach would be to use one UICollectionView and use custom animations so it looks like a new collection view is pushing/popping from an old one, when in fact you're just changing the data for the collection view and reloading. You could even provide animations that are more interesting than pushing/popping.
On top of either of these approaches, you could implement the UICollectionView prefetch API calls to load data just before you need it. That will reduce your memory footprint even further.
All of these approaches assume that you can load the data to display from storage-- that it's not just in memory from recent webservice requests. Your users are guaranteed a miserable experience if your app has to keep requesting the same large data from the web over and over. So, if you don't have the data stored locally already, set up a cache.
Regardless of the approach, this is something you should be able to handle without adopting a library. UICollectionViews are designed to be memory friendly. Your issue is really in determining the best way to manage your backing data's memory use.
I have a process that runs in the background that is adding a lot of Realm records for a couple minutes. I also have a UICollectionView which has a datasource hooked up to a List of those Realm records. I have a Realm notification hooked up to call insertItems(at:) when new records are added.
The problem is that since there are so many insertions back-to-back, the main thread is almost always waiting on the insertItems(at:) call to finish. Therefore, the app is completely unresponsive until the insertions finish.
First, it seems strange to me that insertItems(at:) is taking so long, since only maybe the initial 0.05% of the records are even visible, so I would have thought that UIKit would be optimized to not do a bunch of work for cells off-screen. It's calling collectionView(_:layout:sizeForItemAt:) for every cell, even when they're off screen. I'm surprised that UIKit bothers to call this delegate method on cells which are not on screen or even close to being on screen. The only reason I can think of needing to know the size of cells so far down below the currently visible cells is so that the scroll indicator can be sized and animated more accurately.
Since apparently UICollectionView is doing work for every IndexPath insertion even when not necessary (I'm hoping I'm wrong), I'm wondering if anyone has a suggestion for how to structure it such that the records can still be added as quickly as possible while not blocking the UI. Maybe there's a way to structure this differently with GCD or something?
Right now my table view presents 5 cells at the same time. I load them all up into an array so the "flow" of the UITableView is easier. But since there quite a few objects, the initial load can take quite a bit.
So my question is, is there a way to present the initial 5-7 cells while the rest are loading? Or what would be the practice for this?
The idea: for the first few cells to come up as fast possible, even while we are loading a bunch in the background so the user isn't sitting there waiting for 100+ cells to load.
Also, I am loading this cells with parse (I am getting the user's info including an image).
Thanks!
This may not work depending on where your data comes from and when it gets into your app, but this is what I would do. Allow your array to fill up with the first 5-7 items. Then call reloadData on your table view. Assuming your datasource is hooked up to your array properly, it will load the first few items. Then let your array continue to load until it's complete, and call reloadData again. You could even use this strategy repetitively to continually load new data. Good luck!
I am new to ios sdk, working on app which includes web service calling and parsing JSOn.i have two view controllers on first view i am calling web service on button click and in second view i have to display all record in table view. everything working well , parsing values are also coming properly. but values are coming late and table is displaying empty values. but when i am navigating back and coming again then it will display all button.How to handle this situation?
The beauty of Asynchronous download is making things ready for us in other than main thread. All UI components gets updated by Application main thread, In your case TableView UI updating on main thread and downloading happening in separately. I guess only thing you might missed here is, after downloading finished not getting the notification. Once you arrange notification after downloading process finished, just update your tableView by calling [tableviewobject reload];. Which ll done all reloading of the tableview(this is nothing but refreshing all tableview again). Good luck.
Are you reloading the table view once the data has been downloaded?
Something like this in your Table view controller:
[self.tableView reload];