Should the Model class be a Singleton when using multiple Controllers? - ios

I am designing a To Do List iOS application. I have multiple table views, which all modify the same to do lists array. Should I use a singleton class for the to do list array model, so that it is always up to date, no matter which table view is accessing it?
Would it be better to have a single main controller class (singleton) which contains the model data as well, and has some methods to interact with the data. Then have the other controllers call these methods on the main controller?

Yes, that's the idea of MVC. You have one model, and multiple views of it, with interactions orchestrated by multiple view controllers.
You do not have to make your model a singleton, although this is a very common approach in iOS development.

That would certainly be one way to do it, sure.
If you later decide you want to make your app document-based then you might need to go back and refactor, so think about future use first before you make your decision.

It's totally viable to do so, but you lose the flexibility of potentially having multiple model objects. I'd personally suggest having a singleton "manager" of some sort, that gets the model from your backend (or wherever it's coming from), and holds a reference to the model.

No, the model should not be a singleton. Singletons get overused. It's possible that you may wish to offer the user the ability to create more than one todo list. Maybe one for home and one for work, for example. Each list would be a separate instance of the todo list data model.
Using a singleton would prevent you from having more than one active todo list.

Related

Collecting data from multiple ViewControllers in Swift

I'm having multiple viewcontrollers (in a navigation stack or maybe not) and each controllers collects some data based on users input. In the end I need to use those data in the last controller.
So what would be the best approach/design-pattern to implement this scenario?
If you have (a navigation stack ) and you need to collect data from all this view controllers
the best way Not to use User-defaults , or Singleton
for your case you have to do container of view controllers to handle particular Process . Note (UINavigationController, UITabBarController, and UISplitViewController * is just containers)
For example create account that require 4 steps that collect users inputs , each step is represented by ViewController and at end you need to push all this data to API server ,
So create Parent ContainerViewController of child viewControllers and use Delegation to pass data after every step to ParentViewController , ParentViewController will be leader to allow next step and provide Data for this step . Here is how to begin create Your own Container managing-view-controllers-with-container
Do not use a Singleton
Singletons can be accessed directly from anywhere in the app. You have no control. a-lot coupling in your code and make your objects hard to test in the future
Do not use UserDefaults
UserDefaults is to store user preferences that persist between app executions.Anything stored there will stay until you remove, so it is not a mechanism to pass data between objects.
So you have to use architecture pattern in the future
Architecture
Each ViewController should only take care of their own screen . also viewController shouldn't know about each other. if we do this we will remove a-lot of coupling between our view controller classes.
So You can use Coordniator to be The leader that handle all navigation
Coordniator
and check how to Integrate with MVVM at MVVM-C
also Viper use this technique to handle navigation check Viper
Well, the best approach, in my opinion, is to use MVVM (Model-View-ViewModel) architecture pattern.
1) For each of your UIViewControllers, create a separate class (derive from NSObject if you wish) that's you consider to be the "view model" belonging to that UIViewController. Your view controllers are not allowed to access model classes... that's now a job of your "view model" classes.
2) Create a singleton named, say, DependencyManager. Your view models access it to obtain your models (or at least top-level models if they're hierarchial) and anything else they may need like networking services, etc... The DependencyManager acts as a way your unit tests can inject replacement "mock" versions of your models, network services, etc... when it's time to test each viewModel.
3) Create your model classe(s) that contain the data. Your view controllers had collected various data within the UI controls, and given that raw data to your viewModels. The viewModels may mutate that data (or not) and stick it into the appropriate models they acquire from the DependencyManager.
4) A ViewController is also allowed to ask their viewModel for data. So your last ViewController would obtain whatever data it needs from its viewModel.
Remember: ViewControllers should not directly manipulate your model classes.
Also, your ViewModels should never reference any UI objects, nor even have a reference to its ViewController.
Side Note: I recommend having each ViewModel conform to a protocol which derives from an empty protocol named something like "MockableViewModelProtocol". You can add a single property to your DependencyManager of type MockableViewModelProtocol that each of your ViewControllers can check before they create their ViewModel, in case a unit test has assigned a mock ViewModel for the ViewController to substitute. Another benefit of such a protocol is for quick & clear understanding of the relationship between a ViewModel and its ViewController. Often you'll have not just properties and methods but also callback properties (closure properties).
So there ya go. That, in my opinion, is the best way to not only design a way to manage and access data among a bunch of viewControllers, but to also test all your classes and their use of that data.
And unlike all the current claims that Storyboards block dependency injection and thus prevent testing of your ViewControllers, that's just bunk. By using a DependencyManager, such that your view controller tests inject mocks there, the tests get the same benefit as if they injected a mock directly into the ViewController, and yet the ViewController is still instantiated by the Storyboard. I've shipped a large app quite successfully with this approach.
There can be multiple ways to achieve that,
Pass the data along the controllers until the last one where you want to use it.
Use a Singleton to store the data from each controller. The only issue with Singleton is that it will persist in your app.
You can also store the data in UserDefaults. After using the data, you can clear it out from UserDefaults.
Let me know if you still face any issues.
In my opinion the best way to handle this would be to use a Flux design pattern. There is a framework called ReSwift on github that allows for unidirectional data flow similar to Redux.
Even if you do not use this framework specifically, the concept of unidirectional data flow is perfect for this situation. The state gathered from each view controller will exist outside of any view controllers, the view controllers will stay agnostic of each other, and there will be no need for any parent view controllers to act has higher order coordinators. Then on your last view controller, you access the state and use it however you need.
Another benefit is if you need to break out your view controllers into multiple view controllers through containers, i.e. one screen has 2+ view controllers, you will not need to create more infrastructure to pass data between those, which in my experience gets really messy.

What is the correct way to setup a Model for IOS?

I am creating an app and using Parse.com for Data Storage.
I would like to use a Model for all the different aspects of Parse that I use. For example, if I store some Game data I would like a model to handle doing any finds/updates/entries into a Game model held on Parse.
So I would like a Model to handle all these methods, instead of adding these into the View Controllers.
What is the best/correct way to set these up? I have heard of singletons but not sure if they would be correct here.
At present, I set these up using a subclass of NSObject. I then create all the methods as class methods (no instance methods as there is no instance to create). I then call any class method as usual.
[GameModel classMethodName];
Would this be correct? Is there a better approach or any issues with this approach?
At present, I set these up using a subclass of NSObject. I then create
all the methods as class methods (no instance methods as there is no
instance to create). I then call any class method as usual.
This doesn't sound like a very good plan. The job of a model is to manage the data that your application operates on. That means that your model should have data to store, which means that you should be instantiating your model.
Building support for your back end infrastructure (Parse, in your case) is a good idea. It's much better to put it there than to put it in your view controllers. But where does that supporting code store the game state, for example, or the player's history? It should store it in the model object(s).
Without getting into the whole singletons good vs. singletons bad can of worms (you should Google that), it sounds like you're using class methods for much the same reason that people often use singletons: easy access. Instantiating your class and using instance methods instead of class methods would mean that you have to find a way to share the model with those objects that need it, and that's more work than just using the globally accessible class methods. Doing that work will make for a better application, though.
For example, you could restrict each view controller's access to just those parts of the model that it needs. The game play view controller might only get to see the current game board, and the high scores view controller would only see the player's history. That eliminates many possible bugs -- you'll never have to wonder if the game board view controller is causing a problem with the player history, because it never sees that part of the model.

How to reference variables in multiple IOS View Controllers

I'm asking what is probably a fundamental question but I'm relatively new to iOS and Object Oriented Programming:
Question:
If I have a simple app with 2 Views & View Controllers that receives input from each, how should I structure my program so that I can reference the values that were inputed in each view controller and take these values, add them together (as an example), and then output it to say a 3rd View Controller?
If this was all done in the same controller then I can do it but the issue is where can I store this so that the data is available across multiple controllers?
Fundamentally I'm not sure where the 'processing (addition) should occur. Should this be in another class, or AppDelegate? Is this termed the 'model' in MVC and can multiple View Controllers reference the same model?
I'm sure this is really basic stuff but an example or reference to material will really help clarify this for me.
Thanks
My personal pattern is a variant of the Model-View-Controller pattern. For each screen I have a ViewController, a UIView, a model class to hold data displayed by the view and a helper class to hold all of my business logic for that view. Those classes reference one another so that if you know one you can get to the others. I also link my model classes and helper classes in hierarchies that correspond to the controller hierarchy and that's how I solve the problem you describe. For a given view you can get to its helper and model class instance and from there you can navigate to any helper and model instance for the entire app.
There are probably better ways to do this, but that's how I do it.
You can use NSUserDefaults to store the shared data or you can implement your own shared storage object as singleton, here's one tutorial for creating singleton object in obj-c with demo project.

what's the most appropriate pattern to get and set core data model from multiple view controllers?

Say I have a core data model with a few entities and, throughout the application's lifecycle, I'll be getting and setting properties of these entities from different views.
At least to me, it seems like passing the managed object context around from view controller to view controller and having the controller's code know about the different entities or derived objects goes against decoupling. As a matter of fact, there is a similar question where the only answer suggests passing around the managed object context.
So, in the spirit of MVC, I thought it might make more sense for view controllers to stick to controlling views, and have a singleton model controller through which these view controllers can query the model to feed their views and notify back when the model needs to be updated based on user interaction with the view.
But I'm not sure how to go about implementing the single model controller interface. For instance, here's a few ideas:
make this controller both a delegate and data source to all view controllers?
have the controller be only a data source and use notifications for updates?
kvc/o?
is the whole idea of a centralized bridge from/to the model just overengineering the MVC pattern? That is, is there some reasonable argument in favor of instead passing the managed context around and this not being considered crappy object-oriented design?
Another thing I'm thinking is, if the singleton controller is a delegate and data source, the methods to get model data and update the model should implement some sort of visitor pattern, right? Meaning, for example, if view controller A allows the user to interact with model entity / object A and some view controller B allows for the same for a model object B, and both view controllers rely on the same delegate, the delegate will have to have some way to know which model entity it should target depending on what concrete controller is calling on it.
I'd appreciate any thoughts / ideas
Your idea of a "model controller" makes sense, the problem is I think you may be thinking of it wrong.
It's not really a "model controller," it is the model. In MVC (traditionally), the views communicate with their controller for advice on what to do with interactions, and the controller decides what to tell them based on its logic and information it gathers from the model.
So really, you're simply abstracting the model further, which is a good thing. The idea of a "centralized bridge" is what you want in MVC. Your controller should see a high-level abstraction of the underlying model's implementation, as with all interfaces and layers of abstraction.
As far as implementing the model goes, I'm not sure which is the "best" way to do it, but I can't imagine using the delegate/data source strategy (or sending notifications to the controller) would be detrimental, I'd guess it depends on what you're comfortable with. If you love KVC/KVO, I doubt it'll hurt you. As far as the visitor pattern goes, the logic concerning keeping track of which controller gets which object should be within the model.
It seems to me that your biggest concern is with passing the model around from controllers. It is perfectly alright for the controllers to reference and use the model, but trying to manage their creation and penetration, you're right, is a bit much.
I'd recommend using a Dependency Injection container that can generate the access layer to your model. This way the controllers will get the model passed to them via DI, w/o having to pass around how to create the model classes.
The idea of a single centralized bridge isn't a bad one either, but it would make things a little tricky to unit test.
In the end, I ended up dropping the delegate / datasource approach for a singleton pattern:
I figured the following:
all controllers are collaborating with a single shared
managedObjectContext
the Core Data model itself revolves around a single "configuration"
entity (not the configurations that the Core Data literature refers
to).
This "default configuration" is also what all controllers interact
with, since all other entities exist in the context of this
configuration entity.
So essentially, I have a shared resource which should be accessible in a way similar to a global variable.
So I encapsulated the shared resource in a Singleton through whose interface all other controllers can query and modify the model without knowing much about the internals.
The general interface allows for things like:
[ModelControllerBridge sharedBridge] defaultConfiguration] which
returns the default shared NSManagedObject
[[ModelControllerBridge sharedBridge] newDataSample] which returns a
new NSManagedObject and internally allocates and inserts it in the
appropriate entity within the model.
[[ModelControllerBridge] shouldCommitChangesToModel] which signals
the context should be committed to the permanent store
etc.

How to represent cross-model information in MVC?

I have an application, built using MVC, that produces a view which delivers summary information across a number of models. Further to that, some calculations are performed across the different sets of data.
There's no clear single model (that maps to a table at least) that seems to make sense as the starting point for this, so the various summaries are pulled from the contributing models in the controller, passed into the view and the calculations are performed there.
But that seems, well, dirty. But controllers are supposed to be lightweight, aren't they? And business logic shouldn't be in views, as I have it as present.
So where should this information be assembled? A new model, that doesn't map to a table? A library function/module? Or something else?
(Although I see this as mostly of an architectural/pattern question, I'm working in Rails, FWIW.)
Edit: Good answers all round, and a lot of consensus, which is reassuring. I "accepted" the answer I did to keep the link to Railscasts at the top. I'm behind in my Railscast viewing - something I shall make strenuous attempts to rectify!
As Brian said, you can create another model that marshals out the work that needs doing. There is a great Railscast on how to do this type of thing.
HTH
Controllers don't have to map to specific models or views. Your model doesn't have to map one-to-one to a database table. That's sort of the idea of the framework. Separation of concerns that can all be tested in isolation.
Why not create a model that doesn't inherit ActiveRecord::Base and execute the logic there (think the Cart class in Agile...With Rails).
Controllers don't have to be that lightweight.
However if you have some calculations that only rely on the model/s then you probably just need some sort of model wrapper for the models to perform the calculation. You can then place that into the API for the view so the view gets the end result.
You don't want the logic to be in the view. However you are free to create a database view. Except, rather than create it on the database side, create it as a new model. This will enable you to perform your calculations and your actual logic there, in one place. The pain of trying to keep your views in sync vs. the one time "pain" of creating the new model... I vote for a new model.

Resources