I'm having a hard time wrapping my head around MVVM as I'm in the progress of learning SwiftUI development with Swift for iOS. After reading various tutorials and watching YouTube videos, this is my understanding:
View: The UI
Model: Data layer
ViewModel: "Glue" between view and model. Contains business logic.
However, after doing additional research, I found this article which talks about the role of controllers in MVVM. Now, this confuses me a lot because my understanding was that the ViewModel in MVVM already takes care of what a controller would do e.g. in MVC and therefore controllers would not exist in apps based on MVVM.
Question: Do controllers exist in apps based on MVVM or is the article simply wrong?
It is merely a question of terminology. This author’s choice of terminology is a bit unusual, and I would not get hung up on that. As you dive into these architectural patterns, you’re going to see all sorts of different uses of terminology. (Usually it is the term “view model” that is subject to some creative interpretation.)
Regarding this author’s particular use of the term “controller”, earlier in the document, when talking about view controllers, he starts referring to them as simply “controllers”. This is imprecise, but it is the terminology that he adopts throughout the article.
(As an aside, I would avoid referring to view controllers just as “controllers”, because for many of us, the term “controller” refers to something far more abstract, unrelated to the UI. E.g., see the discussion of “controllers” late in Dave Delong’s excellent video A Better MVC. But let’s set all of that aside and talk about the role of view controllers in MVVM.)
If you are employing MVVM in UIKit or AppKit, then you have a model, a view, and a view model. But you still have view controllers, too. So what happens to them? They do not disappear (unless you switch to something like SwiftUI).
Most/many of us simply consider the view controller as part of the broader “view” layer. A view controller is a UIKit object. It configures views. It is not some abstract object, but rather is an integral part of the UI. In MVVM, it often bears responsibility for hooking up the views to the view model, etc. Regardless of what architectural pattern you adopt, the hallmark of a good view controller implementation is that it is almost entirely restricted to UI related tasks.
So, in short, in that article you reference, the author is merely saying that view controllers are still in the mix (for non-SwiftUI projects, at least). He decided to describe it as a separate layer in his MVVM diagram. Many of us just consider the view controllers to just be part of the “view” layer. It is a question of terminology.
Related
I am bit new to app development in SwiftUI. In last 2-3 months I have developed few small iOS app just to learn concepts. Otherwise I am experienced developer in C#, Java etc.
One thing I am little unsure about SwiftUI is the right set of architecture around developing classes for the project. I mean like there could be couple of ways
We write model classes that represent the data that our application need to hold. In purist form the model classes should only be concerned about just data, I mean the model classes should only hold the attributes that reflect the data.
Say I am writing a Inventory management app so if one of the model is Merchandise item then its attribute could be Id, name, price, barcode etc. In my opinion the model classes should not concerned about View's concern like #Published, #ObservableObject, #State, #EnvironmentObject etc etc. Model should just stick to representing domain only. Correct?
Ideally the model classes should be written as Class not Struct (if I carry over my understanding of OOPS from C++ to Java/C# where we write classes not struct)
The second set of classes we need are views i.e. inherited from View. Undoubtedly these has to be Struct as SwiftUI framework works this way.
Now in between the model classes (presuming they are classes or at max we made them Struct for the sake of SwiftUI framework) and View classes, lots of communication, state change, eventing has to happen to make app worthy of doing something. I mean handling user gestures, creating & editing data which should update screens when user navigate back and forth between UIs.
I found it little hard to connect Model (if they are developed in purist form) and View. Hard in the sense that as I started writing Views and look to implement use cases which involve data editing, reflecting changes in views etc I found pure model classes insufficient. They have to be modified to reflect SwiftUI features like binding, observability, published to sync data between view and model and also between two models.
Wondering what is the right design pattern to connect and communicate between model and view? Is MVVM the right design pattern to be used in SwiftUI based project? If not then what else is right pattern?
If MVVM is right pattern then are there any quality guide or resources or sample SwiftUI projects (gitHub??) I can look at and learn?
I think your hypothesis is wrong.
Ideally the model classes should be written as Class not Struct
Make a distinction between model with and without state.
Model without state should be value type.
Model with state should be reference type.
The second set of classes we need are views i.e. inherited from View. Undoubtedly these has to be Struct as SwiftUI framework works this way.
Value type cannot be inherited. I also think they are models rather than views.
E.g.; struct Model: View {}
They are models, that can be used to build views, hence the View conformance.
The fact that it is of value type also supports that it's not view. (cannot be inherited)
Whether your model has state or not, as long as it conforms to View, it can be used to render a view. This is the design of SwiftUI, taking a page from React, IMO. (I personally don't see React ever bothering with MVVM)
Now since you think Model should be strictly without state, you have a problem.
You need a reference type object that handles all the state and bridge it to the view.
You can follow MVVM. In that case you lose most of the SDK support that builds around struct Model: View, e.g.; #State, #StateObject, #EnvironmentObject, and associated automatic binding and safety checks. You would also add at least one reference type for each of the views, and put most of the control / business logic in it. (where else can you put it?)
So it's in effect a view controller. And you would be doing most of the Control work on a reference type object, without safe guards of immutability. That is on top of all the overheads you would introduce; and since you would pass view model around to be "reusable", you are going to have all the usual bugs caused by shared reference with implicit states.
Take my above assessment with a grain of salt, of course.
Or you can do what official guide do: struct Model: View {} with possible states in it.
The key here, as SDK requires you to put extra annotation, is that state objects are explicitly identified. E.g.; #StateObject, #ObservableObject. And you have to create reference type objects separate from your model. It essentially cuts out the middle man that is view model.
I think this is the most difficult thing for MVVM devs to get used to. You no longer need a view model to do what a view model does.
But shouldn't it be obvious? View model depends on how binding is designed. If SwiftUI has a binding design so efficient, (it does so declaratively without extra object) view model could be automatic.
SwiftUI removes UIViewController, does that mean you can't have Control?
I don't see MVC developers come out and create a Controller for every view.
Same reasoning, you can have MVVM without VM. Design pattern is a #State of mind.
To summarize:
I think the best architecture is official SDK. Learn to walk before you run.
MVVM in legacy sense is an option too. But I think you need to consider the possibility that
traditional wisdom is not up-to-date with latest SDK.
I am trying to keep to the Apple MVC design pattern where the view receives input and passes it on to the controller. To keep the controller thin and to avoid it turning into a bloated GodClass doing all the work, I am attempting to create a subclass of UIView and to receive user input there to be passed to the controller for processing. But I am running into problems with how to best do this in Swift.
In order to pass the user input from the view to the controller my UIView subclass will need to communicate with the associated ViewController, but I've seen posts on SO about how that is not recommended. This Q&A, for example, advises that this is bad but suggests a delegate approach. A comment from the same Q&A also notes that this is bad.
Apple's own MVC example doesn't demonstrate a separate UIView subclass, but uses the existing UITableView, which is all coded within the parent UIViewController, making it a bloated, rather than a thin controller.
How to best approach this?
I recommend you read the apple's doc on MVC pattern since I noticed you do not really understand the principle of the pattern: Model-View-Controller
In order to build lighter ViewController, look at this issue: Lighter View Controllers
You may also interested in MVVM (which used in Cocoa&CocoaTouch for VC thinning)
have a look at this article: Introduction to MVVM
Your experience with bloated View Controllers is not necessarily the fault of your misunderstanding the MVC pattern. The iOS developer Ilya Punchka writes about this in his tutorial post about View Controller Thinning and writes:
A lot have been said on this topic already, even more will be said in future cause unfortunately there is no silver bullet and view controller still stay massive in many projects. Recently Andy Matuschak presented Let's Play: Refactor the Mega Controller! a live coding session on this topic. So you can see it's a well know and still actual problem.
The situation isn't helped by Apple's sample code which also demonstrates massive view controller syndrome! Check out the above links (although the first is in Swift 2.0 and I've had troubles updating his dependancies to Swift 3.0), they both give useful oversight on some ideas around this subject.
I'd recommend taking a look at LetsBuildThatApp episode "Swift: Firebase 3 - How to Refactor View code out of Controller (Ep 23)" here:
https://youtu.be/F3snOdQ5Qyo
Shows a pretty good way to refactor the View code out of the Controller.
I'm still quite new to Cocoa and Objective-C (<1 year). My App now has some 50+ classes, but some of the ViewControllers get quite crowded with code, like 700 lines or more.
My question is: is it fine to have a "large" ViewController or are there patterns for splitting up code into fractions? A lots of the code is implementing delegate methods, thats why I don't have an idea how to move it away.
I know, I can structurize with pragma marks though.
Thanks for any input.
EDIT (Dec 2013): there is a great article from Chris Eidhof of objc.io regarding this subject. He also talked about that subject on Macoun 2013/Frankfurt. Separating out the UITableView protocols are a great pattern.
EDIT2 There are also 2 videos on NSScreencast explaining concepts of refactoring ViewController (episode #102 and #103).
One of the most common causes of large view controllers that I have seen, is lack of separation b/w Model and Controller in MVC architecture. In other words, are you handling your data in your view controllers?
If yes, rip out the model component from VC and put it into separate class. This will also force your thinking towards a better design.
For reference, In View Controller:
Handling of all changes in the UIView and the UI elements contained within.
All animation, transitions and CALayer operations.
In Model:
All processing of data, including sorting, conversion, storage, etc.
IMHO, 700 lines is not (yet) huge for iOS code, I've seen and handled much worse. Of course, if all your VCs are this big, you have a problem.
You should definitely use and abuse #pragma mark, it's very useful under Xcode at least.
Then if you find you got too much code in one file, you can extract functionality to classes or categories, as better fits.
Creating classes can be very rewarding in the long term to manage recurring tasks in projects (ie connecting to webservice, parsing XML/JSON, interacting with SQLlite, logging, etc...). If you are doing recurrent iOS programming, you can create a 'common' library of useful code that way.
Creating categories, especially on UIViewController can help reducing boilerplate code that takes a lot of place. You can (and probably should) also create a common base UIViewController for your app, that will handle stuff like rotation, maybe logging, navigation, etc... in a centralized part of the code.
You should try to identify what your ViewController is really doing.
If you can separate some concerns you can move them to classes of their own. Find out which properties and ivars are used by the viewControllers methods. If you can find a subset of functions, that use a common subset of ivars/properties, these together are very likely to become a class of their own. The controller would then own such a new class and delegate work to this.
If your ViewController is managing some sort of state, eg. you find the same switch statement or if-chain in 2 or more methods the STATE pattern could make your VC much more readable. But basically you could use any pattern that helps to reduce the VCs responsibilities.
IMHO the ViewController is the place were you would connect the model to the views. Propagating model changes into views and handling user interaction with the views are the only things, that should happen there. All other responsibilities, like calculation, network transfer, parsing, validation... should happen in different classes the VC uses.
You might like the book Clean Code by Robert C. Martin. He explores in depth how code could be structured to increase it's readability and reusability.
You can distribute the code using categories depending on the functionality. Refer http://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/Category.html
Prefer the use of NSObject class to manage part of your view controller functions. Main reasons code is more clear and easier to debug
Recently I've been reading up on the MVC pattern and wish to apply it to my iPhone development. However, there seem to be so many variations of the pattern that I'm not sure exactly how it should be applied.
As far as I gather, the view will notify the controller of any actions which have been performed and the controller will in turn update the data model (if required). The data model will notify the view whenever a change to the data occurs and the view then updates it's display of the data appropriately.
In this basic model, the controller only has knowledge of the data model. However, I can't seem to figure out how to employ this design within my iPhone app.
The following page suggests an alternative version of the pattern where the controller has an awareness of both the data model and the view and all communication between the model and view is performed via the controller. It also seems to suggest that the model and view have access to the controller. Would I be right in suggesting that the data model interacts with the controller via some form of notification (notifications or KVO) and that the view interacts with the controller via actions?
Is this second model correct?
http://www.bogotobogo.com/DesignPatterns/mvc_model_view_controller_pattern.html
Many thanks,
Danny
I found Paul Hegartys explanation on MVC in iOS very helpful. see his Stanford iTunes U video. MVC starts at minute 22.
edit
The link of the video doesn't bring you there as expected. it is 1. Introduction to Cocoa Touch, Objective-C, Tools, and MVC (September 21, 2010)
MVC has been around for a long time so there are many variations (or misquotes) to the pattern. Although, the concepts are much the same for most MVC implementations I have seen.
I would focus on how Apple defines MVC. Which can be found in the Cocoa Design Patterns guide and from sample code downloaded from the SDK site (MVCNetworking example).
With iOS you will often will have Models and ViewControllers(which are a merged role of both the controller and the view).
Also, Martin Fowler has some great MVC stuff in his GUI Architectures.
iOS development is very much orientated towards the MVC pattern.
It is usually done with viewControllers and a model. The view is build in Interface Builder, assigned to the controller and the model part is retrieved from elsewhere.
I would say that for Cocoa-Touch the second "version" of the pattern is the one that best describes what usually goes on.
The idea behind MVC is that the model and the view is reusable, but the controller is often fitted to the problem at hand.
This is also true for iOS development, especially if you use interface builder.
The view is hooked up to the viewController via actions/delegates and the model either broadcast its changes through KVO notification or by the controller pulling new data.
There is tons of code available from Apples developer portal and you should start out by looking at some of that code. Having your eyes and mind tuned to looking for the MVC pattern you will see they use it constantly, with the delegate pattern on top to provide event better abstraction
In my opinion, second one is better. Model and view should be separated completely. If view receives notification from model, the view will depends on design of model. By placing controller here, tightly coupled circular-dependency created.
Finally, each part cannot be developed independently, divide-and-conquer strategy is just impossible to use.
My advise for general cases:
Make view and model passive and independent as much as possible. Major mutation must be done with only external manipulation. It should not be changed actively.
Make controller actively controls both of them and other controllers.
In iOS, a UIView is a view which is fully passive. In most cases, all major mutation always done externally by UViewController. And model part should be implemented yourself completely as you want. (Or you can integrate models into controller if it's small enough, however, I don't recommend it)
In some big featured UIView, a sub-scale MVC patterns are used. Fractal!
Sticking to Apple's guidelines, I create one subclass of UIViewController per screen of my iPhone application. However I consistently find that these classes become very large, both in terms of sheer lines of code and number of member variables.
By definition they end up being responsible for quite a number of different concerns (e.g. view life cycle, mediating between views and models, sometimes touch handling, control logic, managing alerts and other UI state).
Not only does this violate the Single Responsibility Principle but it also results in large swathes of code which are near impossible to unit test.
What responsibilities/concerns do you tend to divide off into new classes? What kinds of responsibilities do you think make good candidates for clean separation in the case of UIViewController subclasses?
This is an interesting question and I also struggle on how to properly separate responsibility. It all depends on the context but since testing subclasses of UIVieController can be a pain I try to move as much as I can into model classes. In the spirit of Skinny Controller, Fat Model.
When it comes to tables I have created a base model class for handling all the table view stuff, basically encapsulating what you get when you create a new Navigation Based Core Data project. The in the controller I just forwards the calls to my table model.
I'm trying to keep the methods of the controller as small as possible. Depending on the context I may have several model classes, each responsible for a specific part.
I have also looked into the possibility of using controller factories for getting detail controllers for certain data models.
UIViewController *detailController = [self.controllerFactory controllerForItem:item];
[self presentModalViewController:detailController animated:YES];
This way I can unit test that I get the proper controller for a specific data item without having to involve the parent controller.
With mine, I'm creating categories, abstract parents and using a variety of patterns I've learned in the Java world to reduce complexity and code duplication. But when it comes down to it, I still have one view controller per screen because every screen has at least one thing on it thats unique in some way. There just might not be much code left in the controllers thanks to the infrastructure I've placed around them.