Who should create the ViewModel in iOS MVVM? - ios

I am trying to develop a simple app to understand MVVM but I don't get it really well. I've read some articles, but they are a bit different:
View in different class MVVM
In this example the view is not the ViewController itself, it is a class that contains all the details of the view and it is an abstraction for the VC.
The ViewController creates the ViewModel with some data the it retrieve from DB, Network..
The ViewController talks with the model and manage the ViewModel to update the view.
ViewController is the view MVVM
In this example, the viewController is the view, it does not need other class. The viewModel is not created by the viewController, and the ViewModel of the next ViewController is created by a ViewModel. The ViewModel also has an instances of the Model, so if it needs to retrieve some data, it has instances of the DB, Network..
I don't understand well some things. If the viewModel is retrieving data from Network with asynchronous tasks and I want to display an spinner and get data for fulfil the view. Should I user blocks, KVO or delegates? If I use delegates, the view implements ViewModelDelegate Methods, would be that correct? Am I coupling view with viewModel? I am confused at this point.
If I have a firstViewModel that creates a new secondViewModel for a new pushed SecondViewController,and FirstViewController has to update its view before the user pops the pushed SecondViewController. In this case firstViewModel has to observe secondViewModel and notify the changes to firstViewController once popped, doesn't it?
I also have a question about ViewController creation. ViewControllers are the attendants of next ViewControllers creation? If I create an object that manages ViewControllers creation and navigation should I pass this object over viewModels?
I know they are very similar, but I am confused about which way I should implement and how. There isn't much information and examples about iOS MVVM.
I am not using Reactive Cocoa yet because I want to understand this pattern well first. Though it is in my TO-DO list.
Thank you!

It really depends on why you're using MVVM. I'm doing it right in the middle of the two cases you mention, actually. Here's the two reasons for MVVM usage:
First, you may be using MVVM because you want to organize your code in a way that pulls the logic out of the VC and keeps it clean. In this case, you're using a ViewModel in good OOP form and it's perfectly find to have the VC create it.
On the other hand, you may be intending on UI testing your VC's and therefore want to introduce mock ViewModels. In this case, you want to be handing the ViewModel to the VC. (i.e. dependency injection)
In my view, either is justifiable. You might even have multiple needs in one app. Therefore, I keep things flexible. My approach is to create the VM in the viewDidLoad() method of the VC only if it doesn't exist yet. This allows me to use my normal VM and to do create it (neatly) in my VC, but if I ever need to override it (unit testing, UI testing, alternate view style), I can, too.

The issue comes from the fact Cocoa apps, are by definition using MVC, and you have to try and make MVVM work with the underlying ViewController structure.
I haven't looked at MVVM in iOS, but have done a bit using Xamarin.Forms, where the View is just the XAML code, the view model interacts with the View and the Model. Under Cocoa apps, it doesn't really matter too much how you do the ViewModel part, but looking at your links, I think the second approach is closer to a purer MVVM approach.
I suggest you download the code in the link and have a look to get a greater understanding?

Related

Communication between View Controllers in iOS MVVM

I am working on a simple app to try out MVVM in iOS. I have only two screens in the app. Screen A displays content and the user can tap on settings button to pull up screen B. Screen B allows the user to change settings which affect the way screen A displays the content.
How should I communicate changes made in screen B to screen A so that screen A can re-display the content based on the setting changes? In MVC, I would use protocols/delegate to communicate changes made in ViewControllerB to ViewControllerA. Since view controllers have direct access to the models, I can just pass the updated model in the delegate call. In MVVM, would the communication happen between ViewModelB to ViewModelA or ViewControllerB to ViewControllerA(like MVC).
If the communication is happening between view controllers, what is ViewControllerB really passing to ViewControllerA? ViewModelA? If so, doesn't ViewControllerB knowing about ViewModelA defeat the purpose of reducing view controller responsibility/knowledge?
Thank you for taking time to read the question!
In a situation like this, I would engineer the data stream as follows:
Both ViewModelA and ViewModelB communicate with some entity from a model layer (the first M from MVVM). Frequently such entities are called "services" and contain persistence/network logic.
When the user opens ViewControllerB and changes some settings, ViewModelB makes respective changes to the model.
ViewModelA observes changes to the same model (via KVO, NotificationCenter, reactive publishers or a good old delegate pattern, whatever suits you best) and reacts to them by updating ViewControllerA if needed.
This way neither of your view models need to know about each other, and your model layer acts like a single source of truth for both of them.

Pass data to UIViewController under MVVM pattern

I'm using MVVM for my view controllers and I'm facing an issue that I'm not really sure what would be the best way to solve it. Basically, view controller A shows a table view which is populated with data from view model A. Each cell has its own view model. View model A is responsible for creating these view models and expose them to the view controller. But now that I select one of these items I found that my models (the data I need to pass to the other view controller so it can create its own view model off that data) are hidden behind the view models. View models shouldn't expose the model, but then how could I pass this data to the other view controller? Should the cell view model also expose everything that is needed by the other view controller and just pass that view model? That doesn't seem right either.
After evaluating and playing around with suggestions listed in this post, I decided to go with an approach where the view model of view controller A is responsible for creating the view model of view controller B, considering that it is the one having the data. I got the approach from http://www.martinrichter.net/blog/2015/08/20/navigation-with-mvvm-on-ios/ and I think is the best way to not break MVVM abstraction.
I would strongly suggest using protocols for passing data. You could set the view-controller which is to receive the data as the delegate of the view-controller from which the data would be sent. Delegation is a very widely used pattern in the iOS since much of the architecture of the iOS itself is designed around that.
Let me know if you need help or would like to see some code which accomplishes this.

Keeping an updated model class and accessing it from multiple view controllers in Swift?

I am making an app with swift and xcode. In it I have a model class with user's information in it. I want to display some of that information with one view controller, update/change that information in another, and keep all of the views up-to-date with whatever is in the model class.
I was told using a singleton could work but is not recommended. Is there a better, more accepted way of accessing the model class from multiple view controllers without a segue between them (I am using a tabBarViewController)?
If you want to go "pure" that is follow Apple Best practices where a View Controller is never hard-coded to a global model (more of a pain than is worth, practically, in my opinion):
Subclass UITabBarController to contain the model instance as a stored property (perhaps private(set) is the best access level here, but however you want to expose it safely to other classes -- PUBLICLY EXPOSED AS A PROTOCOL TYPE ONLY OF COURSE.)
Don't forget to set the identity class of your Storyboard Tab VC to this new subclass otherwise your sexy code will not run.
In your (hopefully base class to all child tab VCs) View Controller class, hook into didMoveToParentViewController(parent: UIViewController). Gently downcast (as?) to the UITabBar subclass above, and extract the model, and copy the reference into your local stored property. It will happen exactly at the right time, just as you land into the soft arms of your parent VC.
Happiness!
You can try KVO mechanism. By which if you change a model variable's value that will reflect in another controller. For your reference
https://www.appcoda.com/understanding-key-value-observing-coding/

How to share controller amongst different iOS views

I am coming from a C# wpf background where you can have one ViewModel handling multiple Views. This is a great way to share data amongst unrelated views. However I can't figure out how to do the same thing in iOS, as you seem to need a Controller for each View.
What I am trying to achieve is to have a sign up sequence where the user populates 5 screens of data one by one. I was going to use a PageViewController for this and each click on Next would transfer them to the next page in the sequence. All the while, adding all their input data to a parent model object which stayed around for all five screens, at the end you can submit the whole lot to the database to sign up.
The only way I can see so far to do this is to create five separate ViewControllers, one for each screen of the sign up, and create the navigation logic to display them as you click through. However this a) seems overkill and b) means each subsequent screen and viewcontroller doesn't know about the information the user entered in the previous steps.
What is the correct way to do this in iOS?
You can do it in many ways. If you like to use UIPageViewController, you can actually have one view controller for all steps of the sign up process.
A main view controller would implement protocol UIPageViewControllerDataSource. It has two required methods, which return an instance of a content view controller. These instances can be of any UIViewController subclass, so you could have five separate view controller classes or you could have five instances of the same class.
Xcode has a project template "Page-Based Application". It might be a good sample code for you. There is one class DataViewController and it is instantiated for each page. If your case is really simple then this might be the best solution.
If you use multiple view controllers, you can pass data between them by overriding the method prepareForSegue(segue:sender:). The UIStoryboardSegue object has access to the destination view controller, you can cast it and set up the properties. (I am assuming you are using storyboards and segues.)
Another approach would be not to use UIPageViewController and implement the whole process within one view controller. There could be one view with five container subviews. Initially the first one would be shown, then the second one, and so on. This requires manual implementation of navigation between those steps, but gives a lot of flexibility. It's also more aligned with MVVM, because there is one-to-one mapping between a ViewModel and ViewController.
In general, iOS apps have lots of view controllers. It doesn't seem an overkill for me to use five in your case. It might be more code, but it's less complexity.

Passing references to viewControllers to other viewControllers cocoa touch

The way I am designing my code, with several view controllers, that interact, I have the need to pass data between the view controllers. The way that I am doing it is to "pass a reference", make a pointer, to the target view controller in as a method argument like below:
-(void)aMethodToSetUpInterfaceElements:(UIViewController*)targetCV
Is there anything wrong with this, or do I need to watch out? It works well on a functional level, but what about the design?
There's nothing really wrong about this.
If it works for you, than it's ok. Just make sure to have a weak reference to the view controller, otherwise you could have a memory leak with retain cycle. Read this for more information: http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html
Speaking about design, it's really depends of each case. I could't say preciselly because you didn't give more informations about the funcionality that you are trying to achieve.
Maybe if you want to make your code more generic, to be used in other places or projects, you might consider to perform a delegate to your view controller, but this depends of your views hierarchy and its design. To see more information about passing data between viewControllers, please see this: Passing Data between View Controllers
I don't think it is a good idea to pass a view controller in order to transfer its data if you don't have enough reasons. I tend to exposing the minimal knowledge to another object.
For example, say you have two view controllers controllerA and controllerB.
If all you need is just to pass some data from controllerA to controllerB, you pass the data, which might be a NSData, a NSArray, a NSDictionary or your custom data structure. You should not pass the whole controllerA as an parameter to controllerB. Although you can access the data by using the controllerA.data getter, you have exposed too much knowledge about controllerA to controllerB, which may unconsciously ruin your design by increasing the coupling between controllerA and controllerB.
If you are aiming at handling the view transitions, that may be a good reason to pass a view controller as the parameter. So that you can make good use of its -presentViewController:animated:completion: to present a modal view, or push it into a navigation controller, or you probably want to get a reference to its view property and customize your own UI presentation.

Resources