Persisting a datasource between multiple views without shared root view controller - iphone

I'm currently working on an app that uses a UINavigationController inside UITabBars. The tab bars correspond to both UITableViews as well as a Map View. However, the root view controller of the app is not the parent, or direct parent, of the UITableView custom controllers and map view controller. I also have a p-list that creates NSDictionary objects; it is the datasource that I am using to populate entries in the tables and the map.
So, without a root view controller, how should I create the NSDictionary objects from the data source? It seems to me that the easiest way is to simply recreate the object in each view controller for a view that needs the data. Because I don't have that many views and the p-list isn't that long, memory shouldn't be an issue. However, I do know that this is all very inefficient.
Is there any alternative implementation so that I don't have to recreate the NSDictionary in each view controller?
This tutorial featuring the singleton guide neatly explains everything:
http://www.cocoanetics.com/2009/05/the-death-of-global-variables/
My only worry now is if multiple view controllers each call the singleton, wouldn't they all be generating multiple instances of the NSDictionary, and couldn't that conceivably still take up a lot of memory?

You need a data model object that stores the data for application.
A data model is a customized, standalone object accessible from anywhere in the application. The data model object knows nothing about any views or view controllers. It just stores data and the logical relationships between that data.
When different parts of the app need to write or read data, they right and read to the data model. In your case, view1 would save its data to the data model when it unloads and then view2 would read that data from the data model when it loads (or vice versa.)
In a properly designed app, no two view controllers should have access to the internal data of another controller. (The only reason a view controllers needs to know of the existence of another controller is if it has to trigger the loading of that other controller.)
The quick and dirty way to create a data model is to add attributes to the app delegate and then call the app delegate from the view controllers using:
MyAppDelegateClass *appDelegate=[[UIApplication sharedApplicaton] delegate];
myLocalProperty=appDelegate.someDataModelProperty;
This will work for small project but as your data grows complex, you should create a dedicated class for your data model.
Placing the data in an init method or a viewDidLoad won't work because in a tabbar the users can switch back and forth without unloading the view or reinitializing the view controller.
The best place to retrieve changing data is in the viewWillAppear controller method. That way the data will be updated every time the user switches to that tab.

In practical terms, a data model is usually either placed in some kind of a singleton (either your own, or the app delegate which is a kind of singleton).

You should read up on Model-View-Controller (MVC) architecture. Specifically, you'll probably want to introduce a data model where you would create and populate the dictionary during initialization and then access it from all of your view controllers.

Related

retain entries in UITableView

I have the following (view) controller arrangement:
an uitableview --(embedded in)--> navigation controller --(embedded in)--> Tab bar controller --(modal segue to)--> button in a view (uiviewcontroller).
description of my problem:
The view with the button is the initial view of my app. Pressing this button leads to a tableview in a tab bar. At the beginning the table view is empty, but you can manually add information on the cells, like names. However, once you go back to initial view (with button) and press the button again, the previous entries in the table view are erased.Can somebody give a hint how to retain these entries with the given arrangement. Thank you very much in advance.
You can use the singleton pattern. It will create a shared instance of your object, that you can access anywhere. You will then be able to write in it when the user adds a row in the table, and read it when you come to the tableView.
Here is a bit of help : Singleton pattern
EDIT : you can also use core data, but it may not be appropriate in your situation (plenty of docs on the web about that one)
This is quite a question as it really isn't about the interface per se. It is more to do with general Object Orientated Programming and the life time of objects.
Basically your data needs to be stored higher up the object hierarchy. It needs to persist across construction/destruction of the interface objects. This could also be done by storing the data in persist-able data store such as a DB or file but you would still need to store the means to extract the data or subset of data from the store.
If you wish to persist the data you could store data in a singleton data class and reference it statically or store it in your UIApplication object and pass that down the hierarchy as you create each object. you would probably have to subclass each object and add a new constructor passing in a ref to the data.

Initializing a View Controller

When a view controller is first instantiated, it usually creates or
loads objects it needs through its lifetime. It should not create
views or objects associated with displaying content. It should focus
on data objects and objects needed to implement other critical
behaviors.
The above is from the iOS reference :
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10
The documentation goes on to describe a view load sequence with Storyboard.
My question are :
1
Since a view controller would be associated with a nib file, which contains view objects; And its "viewDidLoad" method seems to be designed for configuring view objects at load time. So how should the documentation's suggestion :
"should not create views or objects associated with displaying content"
be interpreted ?
2
Does question 1 related to whether we use Storyboard or not ?
Not sure I get your question right, but here's my explanation:
initialization and view creation are two separate steps. Let's say I have a view controller with table as IBOutlet which should display a list of recipes stored in core data. In my initialization method I'd fetch the data from CoreData and store it in an array or fetched results controller. I don't need table for that, hence I do nothing with self.view property (which calls the viewDidLoad if there is no view yet). In viewDidLoad I call [tableView reloadData] to redraw the cells so that they display the data from my controller created in controller's initializer.
I don't think it's related, but storyboard should be mere scaffold for your view controllers replacing separate nibs with single file.
The statement you quoted has a lot to do with mobile device limitation and design efficiency. It does not relate to Storyboard in particular.
By "instantiating", the documentation meant the -(id)init; call. When this happens, the controller "prepares critical data, but not creates views". This means the controller evaluates a xib file, and constructs an internal hierarchical representation of the views upon init. This step involves only RAM and CPU.
View controller only creates views when it's pushed into the navigation controller, or view transition animation (that's when viewDidLoad kicks in). This is because views are expensive. It involves GPU and Video RAM. Video RAM is much more limited than RAM, it's not efficient to just create views (back buffer in VRAM) when it's not necessary to display.
If you look at your project, you should discover some view controllers being initialized but are not immediately required to show. Without such design, VRAM will drain quickly for no reason.

Use UIViewController vs separate datasource object to manage model objects?

I'm writing a simple iOS app that uses a table view to display information from a set of model objects (each is an instance of "NTTrip"). I'm deciding between using a single subclass of UITableViewController to manage both the view and the set of model objects or whether I should separate the logic of managing the model objects into a new object that would act as a data source to the table view (i.e., sort of split up the logic into a "view controller" and a "model controller"). Is this a good idea or would I be adding extra complexity into a system that doesn't necessarily need it?
In general I like to split specific responsibilities like a UITableView's datasource out into non-UIViewController controllers. I think that that separation makes it easier to test and maintain my controllers.
However that doesn't always make sense. If you're considering using a UITableViewController then that implies that you expect your table view to fill the screen and here are probably not many other behaviors your UIViewController subclass would be responsible for. I think multiple controllers would be unnecessarily complicated if there are not clear independent responsibilities for each controller.
One alternative might be to have a single UIViewController subclass which acts as the table view's delegate and datasource. That controller can call out to some NTTripService controller which can be responsible for loading and persisting your NTTrip objects and make them available to many UIViewController subclasses for display.
Controllers are typically the most complex part of your app and are expected to talk with the data and manage the view. In iOS you typically don't have data controllers. As such, your table view controller should also communicate with your model to display the proper data for your table view. By having another data controller talk to the data model and act as a datasource, what else would your original controller do? The other extreme, of course, is to parcel every bit of work into a separate controller…but you see the problem with that.
Bottom line—your single table view controller should manage both your data and your table view—that's what the controller is meant to do.
A wrench though—if your same data is managed (edited, used) by other controllers, you may want to factor that out into a service as Jonah suggests. Otherwise, it's just unnecessary work and complication.

where to store main table view data? (appDelegate or rootViewController)

Any advice on where to store the main list data for an iPhone application like the following?
NavigationController based
Level 1 (main screen) is a List of Items. Hence it uses a table view (table of items)
Level 2_EDIT: Is a view you can get to from the main screen by clicking EDIT. Here you can add text to be added to the main view list
Level 2_DETAIL: Is a view you can get to from the main screen by clicking on a cell.
Now assuming the implementation is (rough overview):
* MainView - appDelegate (holds UIWindow & UINavigationController)
* RootViewController - table view of the main items list (? variables here ?)
* EditViewController - input text to add to main list
* DetailViewController - shows detail of record
Question - Where to hold the NSArray that keeps the main list of items? Should it be in the RootViewController where the Table View exists that displays it? Or should it be higher up in the ApplicationDelegate? I note that when you go from RootViewController to EditViewController, then in this edit view you would have to ADD items to the array, so would it be easier for the code in the EditViewController to access the main array from the AppDelegate (as opposed to the RootViewController)?
(Note - still haven't made an app that has a specific model object, re MVC, yet, so not sure if this should come into the picture.)
Your data becomes the table view's data source, and although it doesn't have to, the view controller that contains the table view often does the data source's role. The view controller can also be a delegate for the EditViewController, so the EditViewController sends a message to it so it can update the array.
Apple's CoreDataBooks sample project show similar architecture. You may want to take a look.
Having the array in the application delegate is often not a great idea. Although it can give you a little bit of convenience, now your classes totally depend on your application delegate unnecessarily.
Your table view shows your data. This corresponds to View in the MVC design pattern. I assume RootViewController is the view controller of the table view, which acts as a Controller in the pattern. Your data, the location of which is not decided yet, corresponds to Model. The role of RootViewController becomes connecting the Model and View.
The ideal, or the reason of the MVC pattern is to isolate the model and the view, so the model can work with other views with appropriate controllers, and the view can also work with other models with appropriate controllers. For example, your RootViewController will provide the table view with data. It will specify the data in the language of table view, e.g. the number of sections and rows, the contents of cells, etc. If you want to present the data in a different way, for example a graph, your controller will access the same data (model) and provide the graph view with a different representation of the same data. The model need not change, neither do the views. You write only the controller, for each combination of a model and a view.
Ideally, therefore, you will have a different class for the model. In this class, you will store the array, and provide a general interface for controllers can interact with the data.
However, it's often not that necessary, either because it's unlikely that you will use the model class often again, or because the model itself is way too simple so it can be easily implemented anywhere. For example, if your data for the table is a simple array, an NSArray object is often sufficient for the model's role. Therefor, here comes an idea that to combine the controller and the model into a single object.
This is why it makes sense that your table view controller often acts as the data source of the table view.
However, storing the data in the application delegate is a completely different idea. Now the application delegate becomes your model, but which does not make sense, because the application delegate is only used for the specific application. Why would you have a separate model object that totally depends on a single application? Also, if your table view directly interacts with the application delegate, it means that now your view cannot work for other applications either because it now depends on the specific application's application delegate.
Often the reason why people are tempted to have data in the application delegate is, that the application delegate is easily accessible by any objects in the application by using [UIApplication sharedApplication].delegate. The M-V-C relationship is not always very simple. For example, your EditViewController also need to access the same model. To do this, you have to write some code to make the model accessible by both the table view and the edit view. If you have the data in the application delegate, you don't need to do anything, because you can magically access the array by accessing the application delegate.
But that's all. A few minute's saving in your coding time, for the price of ruining your software architecture. I'm not a fundamentalist, and I do sometimes use application delegate to store some data when I'm absolutely sure that it's not worth to provide well-formed interfaces, but it's rare.
So how should you connect your edit view to the data merged into the table view controller? There could be multiple ways. What I suggested before is let the edit view controller has a weak reference to the table view controller (delegate) and send a defined message, for example - (void)editViewController:(EditViewController *editViewController) didFinishEditing:(id) someData. In this way, you can use this edit view controller with some other view controllers as long as they use the same protocol. But others may implement different interfaces for it.
You need to store in the appDelegate,as you can acees the data in anyviewcontroller then.But if you use rootviewController,then you can only send data to next ViewController then,not to the 2nd or 3rd ViewController directly.
Hope it will help you.
Good Luck

iOS Development: How can I return data from a modal view?

If I have a parent view controller that displays a modal view with a textfield to collect data from the user, what's the best way to return that data to the parent view controller? Currently, I assign the parent view controller as a delegate that's called from the modal view when the user enters the data. Is there a simpler/better way to return data from a modal view?
Thanks so much for your help!
Personally, I would have the modal view dispatch an NSNotification that passes the data. A delegate works too, of course. I think that both a singleton and a delegate mean tighter coupling, but I understand that some might disagree.
But I do use singletons, too, if I need access to data stored centrally from many different places in an app. I just wouldn't use it simply to pass data from a view to another.
When needing to store and pass data around I usually have a singleton class that I use throughout my app. This keeps things a little cleaner in separating my views from each other. Here's a simple implementation:
http://www.galloway.me.uk/tutorials/singleton-classes/