swift segue new viewcontroller stuck when other tasks loading on background - ios

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.

Related

How to programmatically create a new UIViewController in Swift

I am new to the world of iOS development and Swift, and have run into a problem. When my app starts, it is to connect to a web service, and download a JSON string containing information for "posts", then, it should load the first post into the first view. After that, the user can swipe left or right to load a new view with the next post. I figured that I could use something like this to do that:
let nextView:ViewControllerName = ViewControllerName();
self.presentViewController(nextView, animated: true, completion: nil)
However, this infers that I already have another UIViewController created and ready, but since I am dynamically loading data, I will have to create new views on demand and create an indefinite number of them.
How, then, can I create a new UIViewController, add controls to it, add controls (including custom controls), and populate the controls with data all in Swift code? Could I somehow integrate it with storyboards?
You could have one UIViewController which contains a paging scroll view (UIScrollView) that contains the views to be displayed.
When the user swipes, you just populate the view to be displayed with the appropriate data. A common pattern is to have 3 views in the scroll view with the next and previous ones already preloaded.
Trasform your JSON response into an array of UIViewControllers (factory pattern). For each item you can create something like - (UIViewController *)viewControllerFromObject:(MyObject) object
Install ISScrollViewPageSwift
Integrate it
Search for "UIPageViewController" tutorials. You could also use a third party library like "iCarousel" which makes it a little bit easier.
https://github.com/nicklockwood/iCarousel
But: creating a new view dynamically on demand asynchronously over the network will create a very poor user experience. On iOS the everyone is used to a very fast and fluid user experience - as soon as the user swipes he wants to see immediately the next view. But a network request takes 0.5 seconds - 10.0 seconds, depending on you network connection. It would be better if you preload some pages to have them already in memory. And as soon as the user has viewed some of the preloaded pages you can preload more of them... and so on... indefinitely.

Using a tabbar for controlling the tableview data in iOS without using storyboards

I am building an app which mainly shows a tableview. In this tableview I have some custom table rows. The table rows are filled with data received from the server. I receive multiple kinds of data from the server. I will store it in arrays.
For example, I've got three kinds of arrays. Each is filled with different kinds of data received from the server. See below:
(NSArray*)carList_
(NSArray*)motorcycleList_
(NSArray*)bicycleList_
The actual program that I've got now, only shows the carList in the tableview. Foreach car in carList, there is a table row.
The thing that I've in mind to do is a little bit tricky. I want to add a tabbar at the bottom of the screen with three buttons. When I press the first button, I want the table to be filled with the carList. When I press the second button, I want to fill the table with the motorcycleList. And when I press the third button, I want to fill the table with the bicycleList.
As you can see, I will use the same tableview. I will only refill it with the data I want to see. Is this allowed in iOS? Cause I read something about that the tabbar is for multiple views, and I only want to use it for changing the data in my table. Only the fourth button I've planned for future development will open a new view. If it is not allowed, what is a good alternative do do it? Buttons maybe? I searched the web for what I want to do, but it seems that my idea has never been used before, I think my idea is not allowed in iOS.
At this moment I've a initialViewController (with almost no code cause it is used only to initialize some things of the server. It acts like a splash screen) and I've got a rootViewController which does the works. In the rootViewController I've got my Table with Table rows and it has the different arrays of data which are retrieved by a method that is called when the rootViewController is loaded.
I am programming without Storyboards, because I'd like coding and I want to understand how it works 'underground'. What is a good way to implement the tabbar if it is allowed what I want to do with it? I don't think a standard tab controller will work, because I am working with only one view.
Of course you can use the UITabBar solution. However this might be not very useful and this is not the idea behind the UITabBar. You can instantiate the same TableViewController vor each tab. In this case you can use the same class but you have up to the instances of this class when the user cycles through the tabs. This will be obvisously a waste of memory.
Your descriptions sounds like a UIToolBar with a UISegmetenControl in it might fit your needs better. You can also place it at the bottom of the screen and you will need just one TableViewController for your data.
UISegmentedControl is designed for switching between different data representations. It is also commonly used for switching between table datasources. But it often appears at the top of a view. Take a look at Top Charts tab of App Store app.
Tab bar is designed to present different views for each tab. Here are progress steps to achieve your result:
Use different instances of table view controller for each tab
Configure each instance for displaying one particular array, depending on tab position
Keep arrays in external (outside table view controller) storage, instances should have an access to it
It's better to preload data, while user is examining an active tab. Hence, load data outside of table view controllers, possibly in AppDelegate. Use notifications to update table view when data are available.

Display cells while others load in the UITableView?

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!

Show activity indicator while changing views (Segue) and load data for next view (API)

Umm I really need some help
I have a search view, when user clicks the cell (basically a game), the view changes to a Game View. Atm I was not using any async stuff so while the game view loads, the app kinda hangs for 2-3 secs on the search view after clicking the cell (since the viewDidLoad method of game view loads all data from web API)
What I wanted to do was when a user clicks game in searchView, the gameView instantly shows up with just a blank view and a Activity Indicator meanwhile the data is fetched from API.
Once data is fetched, the gameView (which is a tableView btw) reloads the data and shows it accordingly from the fetched data.
If it makes any diff. I am using static cells for gameView and thus not using cellAtRowIndex code.
I have attached images for some of my methods I tried to use as per my searching on SO for AFNetworking, async etc etc.
The table IB elements are filled from data in a separate function showGame, I am calling this function in rowsForSection since table will be reloaded after block completion. Excuse me but I wasnt sure what would be the best way to reload table or rather show the data.
Atm my app is showing me my default static content which I created in interface builder (and with only 1 row). AKA the table is not being updated. I used breakpoints to check and yeah the showGame is getting correct data, passing correct data to IB elements. Even the execution is reaching the point in code to return 5/6 rows BUT the actual app/view is not updating properly.
For those who want pastebin text code, here it is:
.m file where async code to fetch game from API is
http://pastebin.com/p2FETbku
.m file of my gameView class/tableView which shows the table view and data, this file also has the showGame method to show the game data fetched from above class
http://pastebin.com/cWtSKPw0
Please excuse my code or any small mistakes, I am still in learning phase and just started 3 weeks ago.
The static cells were working fine before I was using async method, somehow its getting messed up during/after that reloaddata
One point that I think you are missing is that execution of this statement
GDgameViewController *gdv = [[GDgameViewController alloc] init];
doesn't return the tableViewController hence the tableView that is currently presented.
So in your function +(void) fetchGame:(NSString *)gid what you are reloading is the tableView that is not presented.
To help you further I have created a project for you which use a bit different approach to do your work but it does it optimally. You can find project here. If you don't know how to use gitHub, don't worry just download the zip file. Please make this count as

Performance issue when reloading tableview section

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.

Resources