So I have a main uiviewcontroller and it goes down three levels with sub controllers. I am loading a list of data in the main top level uiviewcontroller and passing that down each level which works fine.
I need to load more data for each item in the list. Right now I am loading that data on the fly when the lowest level view gets loaded. I need to load some of this data in the background in the top level view which is fine but I find myself loading this data twice if the current view hadn't been loaded yet. I am thinking of using a global variable (a list) to load all of this data and just use that in each of the subviews. I feel like the global variable is not the way this should be done.
How can I load data in the top level view and have that propagate down to the lowest level views that have already been displayed?
There are various ways to handle this.
Having to set up links to pass data along each step gets old after a while. When I'm writing an app that needs to share information across multiple levels of view controllers, I'll think seriously about using a data container singleton. See this SO thread for a description of several options, along with a link to a developer blog including a working example of a Swift-based data container singleton:
How do you share data between view controllers and other objects in Swift?
Related
Where do you usually load data when using a UIViewController?
When I say "loading data" I mean: API calls to fetch it and its manipulation.
Do you load it in the view controller initializer, or load it before to initialize it and pass it? Or do you add the code to viewDidLoad?
Also, what about the data for the rootViewController? The one that initialises from storyboard when you launch the app?
Do you load it in the view controller initializer, or load it before to initialize it and pass it? Or do you add the code to viewDidLoad?
Usually this done inisde viewDidLoad e.x in MVC you call the controller to load the data and refresh the contents of the vc like table/collection , regarding sending data case this known as dependency injection
Also, what about the data for the rootViewController?
rootViewController is same as any other vc
First of all let me suggest not to have data loading code in ViewController if your app is not very very simple. It would be a better practice to have it in a separate class. Check out MVP or VIPER design patterns for more info.
As for when to load your data (after view loaded or before) is more of a UX decision.
If you start loading after, of course, screen might be empty for a while, it would be good to have some loading indicator on the screen so that users do not get confused. Whether users will see empty screens often or not depends on whether you store your loaded data permanently (in a local DB), have some run time cache, or non of that. If you have some caching, empty screen will be visible just once, because if data is loaded and cached you will show that and update the screen after new data is received.
You can also start loading data before view is loaded (in loadView()) or may load some minimal data for the views which are not visible (so that they are not completely empty when opened) and then load full data after view is loaded.
Any approach you choose is highly dependent on what kind of user experience do you want to provide, also on how long it takes to load your data.
Answer in one line is viewididload but below is the actual structural method.
So for this you can have multiple answer the most popular answer for these days would be using MVC/MVVM. So let's discus about MVVM with delegate/protocol
Model - your data.
View model - here you initialize/modify/handle your data.
Viewcontroller - viewdidload - here you can initialize your view model and interact with the data that can be provided by view model with the help of delegate-protocol mechanism.
What is the best way to have multiple UIViewControllers that can be accessed from a side menu and without having to re-download any data each time the view controller is shown?
Say for example I have three view controllers, one is a homepage that shows recent notifications, one is a news page that shows recent articles and one is a page that has a collection of images. When each view controller is loaded, data is downloaded from a remote server and displayed - if the user switches to another view controller and back again I want the previously downloaded data to be shown immediately without having to be re-downloaded (until a UIRefreshControl is used or similar).
Off the top of my head I can see this being achieved in 4 ways:
Store the data in a singleton and load the data from this if it has been previously downloaded, however, this seems to go against general practices that I have seen and also doesn't seem efficient - especially if there is a lot of data and/or multiple view controller.
Use a UITabBarController that selects the index based on the side menu instead of the traditional bottom bar, would this cause issues if there were 10-12 items on the side menu?
Cache the data to disk (using NSCache etc) and instantiate/dismiss each view controller as needed, the view controller can use the cached data - only one view controller will exist in memory at a time.
Use some kind of customised container view that caches the view controllers and loads them as they are needed, feels a bit hacky and not very efficient?
What are the best ways to achieve this? Most tutorials I see just show how to segue/present view controllers but I have struggled to find anything that explains how to preserve the data that was downloaded on them.
Just as an FYI. If one of your ViewControllers is supposed to "show recent notifications/articles" then caching data won't work because it might not be the most recent unless you pull from the server every time. (Unless the recents are getting pushed and even then you might have huge sync issues if you don't pull every time.)
That said, you options 1 and 3 are effectively the same, the only difference is where you are keeping the information.
You should not be using a tab bar controller. If you can't use UISplitViewController then you should make your own custom container view controller.
As for the caching issue. I would implement some sort of caching mechanism for each endpoint. It could store in ram or on disk but I think in ram is better because the data sounds pretty volatile.
Set it up so that when a view controller makes a "network" call, the function it uses calls the closure with the last data it pulled and then optionally can make the network call again and call the closure a second time with the new data. This way the VCs will be very responsive in getting data up ASAP and still pull in the new data on every view will appear.
I would go with a combination of option 3 and 4.
There are many formats you could use to cache the data to disk. You could use a database like CoreData or Realm, or write directly to files as a Plist, JSON, NSKeyedArchive.
You probably should build a container view controller as well. Thats what a TabBarController is after all. It's pretty easy to do and the docs cover what you need to do. This will make you app more efficient by only having to load data from the database/file the first tome you go to the view controller. Then when switching sections, it can just show the VC thats already been loaded.
Every single time I need to create a simply tableview that is populated by a simple data set retrieved from my web server which has its code executed like this: SELECT * FROM table I find myself spending two blady whole hours trying to get the new view controller up and running as I try to update some variable names, copy and paste the required code from my previous view controllers. etc its ridiculous.
This is the end result for all my view controller pages where each will contain different data sets depending on the web service urlĀ being called:
Here is a link:
Link to downloading staple code .h .m and .xib files
This view controller contains a few simple elements seen throughout all data viewing pages:
UITableView
Titled header views
table indices.
refresh table control feature
data connection retrieval code
data connection succeeded
data connection failed
setting up all my bloody delegate and data source methods.
I find myself having to copy and paste all the staple code, functions, variables, properties, and IBOutlets; and to be frank, its getting ridiculously paintaking to have to repeat the same procedure over and over again but changing variable names between the different view controllers.
This is why I believe people create simple component like structures that make it easy for users to get tables setup and up and running.
How can I reduce this big chunk of code:
to something that will allow me at most do this:
Create a new view controller
Setup xib file
create appropriate IBOutlets, and hook them up to the xib.
Here's where it needs to change
I need to now simply able to write something like this the next time I am goin to create another data viewing View Controller:
[self setupTableForDataSetType:]; //This will make sure the tableView knows which data set its dealing with and so therefor know which DataModel classes to use
[self retrieveDataWithWebServerURL:]; //of course so that the connection code can make the right server connection with the URL given for the data set required.
Thats it. So that it is super easy for me to create the tableView pages desired and show the results quickly! Atm I have the same code everywhere in different view controllers.
Whats the best way to go about doing this?
Create a viewcontroller with all your customizable values as properties and reuse changing its values.
Well, subclassing is probably the best (maybe only) way. I've done something like this for tables with an index, since they're a bit of a pain to set up. I created a IndexedTableViewController that handles almost all the load. I make my app table view controller a subclass of that controller, and then I only need to feed a simple array of custom objects to the method, convertArray:usingSectionKey:secondarySortKey:(implemented in the IndexedTableViewController) which creates the sections and the index. The only other method I have to implement in my app table view controller is cellForRowAtIndexPath:(though I would have to implement more, especially didSelectRowAtIndexPath:, if I were doing more things with this table).
Your needs sound a bit more ambitious than this, so it would take quite a bit of work to make a superclass that would be general enough to work with most of your apps. A method like setupTableForDataSetType: could be quite complicated if it needs to handle many different data types.
I'm using Apple's UIPageViewController template, which includes a "ModelController" class. I use this class to return individual pages in the form of a viewcontroller, but how much setup is the Model class responsible for? For example, I have a plist that contains an array of image layout info for each page. Should the model hold the entire array, and then set each viewcontroller with its specific layout information, or should each viewcontroller just get its own layout info? What exactly should the model take care of?
I would suggest to make the model as heavy as possible, and the viewcontoller as light as possible
Another thing is to use lazy initialization for the image in the viewcontollers
So ideally the model will contain the array of the names of all the images that you wish to load, and each time a new page is generated load the image and add it to the viewcontoller that you will create.
The viewcontroller will have all the information needed for it, this means that you could use this same viewcontoller as a stand alone controller outside of the context of pageviewcontroller
So the model will be only responsible to load the required variables,
the access to these files, the loading of the images will be done in the viewcontroller, in a way that viewcontroller will only receive strings as parameters, and the loading logic is done inside the viewcontoller, hence decoupling the views as much as you can
I'm building an app that has views that are build programmatically. That is, I am fetching data from a database that contains information on things like the number, size and placement of buttons in a view. At some point, there will be code that uses this data to instantiate new subviews and set them up. My question is, where should this code go? The view, the viewController, or somewhere else. It seems to me that this is a grey area regarding typical MVC principles. Should a view accept data, and then know how to draw itself using this data? Or perhaps, a viewController is responsible for building all the various subviews, and then simply adding them to the view.
Thoughts? Thanks.
I agree that it's a gray area. Personally, I make a decision like that based on whether it's the data that needs manipulated or the display of that data. For example, a view controller displaying a date may need to process various dates (ie, a data represented as a DMY struct vs. a date represented as a seconds count from some reference time) into a format suitable for the view, while the view itself may be only capable of receiving one particular format (ie, DMY) and is responsible for displaying that. That's the sort of line I tend to draw between the two -- displaying data (the view) vs. interpreting data (the controller).
In your example of reconfiguring a view I would probably put most of the logic into the controller since it involves interpreting the data. I would design the view to accept configuration details such as how many items to display and what sort of layout format to use (think of a UITableViewCell), but I would design the controller to interpret the data to decide how many items and what to put in the various fields within the view (like a UITableViewController).