Hi I am new to MVVM as well as to iOS programming. I am trying to convert my sample app into MVVM pattern.
Here is my simple use case-
I have one view controller class which holds information screen - InfoViewController. I has 4 informative labels with some text. Currently it is implementated in MVC pattern. viewDidLoad method binds iboutlets with text which is static. How can I convert this into MVVM? Here is my understanding
InfoViewController will have InfoViewModel which will be initiliase in viewDidLoad
Struct InfoViewModel will have
a.firstLabelText b. secondLabelText and so on..
In viewDidLoad method I will bind iboutlets with viewModel properties which will return text
Currently this text is static but it may come from web service in future so should I create model class here?
Is this correct way for this use case?
The best way to bind your view and view model is to include a framework that supports you.
E.g:
https://github.com/ReactiveX/RxSwift
https://github.com/ReactiveKit/ReactiveKit
I use RxSwift to bind my view model to the view. A nice introduction to mvvvm with rx can be found at https://academy.realm.io/posts/slug-max-alexander-mvvm-rxswift
Related
I'm trying to understand how to properly implement MVC in swift. Heres my scenario:
I have a signup page with 9 UITextFields, and they're all being made programmatically, and therefore being anchored to the view programmatically. As you can imagine this would be a lot of repetitive code to have in the SignupViewController class file.
Is the convention when following MVC to keep the setup of these text fields in the SignupViewController file, or are you supposed to have a separate file such as SignupView that contains all the text field setup code?
Even though UIViewController has the word "controller" in it, I believe the majority of iOS devs these days assign the UIViewController to the "View" side of MVC. The UIViewController is chiefly specific to a particular view only, plus may manage its subviews as well (until this gets too messy and a container view is added to allow for a nested UIViewController).
In MVC on iOS, the view controller can easily become polluted with business logic, model management, etc... which is why many people jokingly refer to "MVC" in iOS as "Massive View Controller". To combat this, consider using an MVVM architecture instead, which not only keeps the VCs small, but also moves the business logic out to a separate "sidecar" coupled to that ViewController, called a ViewModel. This allows the business logic to be unit tested without any UI involved, making testing much more reliable and easier to read and maintain. With that said, the creation of these 9 controls would still belong in the ViewController.
As for programmatically adding UITextFields to your view vs viewController, if this is to be done just for this single scene, then I'd stick it into the viewController. If you expect to want to reuse the set of them in other scenes, then making a custom view or control containing them would be better, like is typically done for custom cells of a table.
Finally, consider simply using a Nib or Storyboard to layout your scene. Apple has provided so much power to layout and maintain scenes via nibs and storyboards that you're really missing out to go the programmatic route. I find it very rare that I side with programmatic approach. The auto-layout warnings in InterfaceBuilder alone are worth gold to me, and as Apple continues to raise the bar and change layout rules, I can't imagine trying to keep up programmatically when I can't afford to test every device and iOS version combination. And yes, it's possible to do MVVM with dependency injection and storyboards. I do it daily.
Answer to your question is that it has nothing to do with MVC .
AS iOS/Mac developers, we use Interface builder and auto_layout to achieve most UI #IBOUtlet/ #IBAction. This is the V side of MVC.
Typically, If you have data, database, json or whatever formats, you need to model them and handle logics. That'M of MVC.
The C(Controller) side of MVC is a kind of glue between M and V. In most cases of mobile , you can think Controllers are all C you need.
So controller class is the only portion you need to put code to simplify everything.
In your case, 9 UITextfields should be ideally put into V side job. Please don't write code for them unless there is no better way to do.
I don't agree with above statement about using Interface Builder... I prefer to write most of my views in code and also set the anchors that way as well.
to minimize the file you can create an extension of the ViewController in a separate file to contain all of this code.
so for SignupViewController you would create a new file called SignupViewController+SetupUI.swift.
import UIKit
extension SignupViewController {
// add your setup methods here
// as just an FYI you can call the methods you create from your
// SignupViewController file just like you would any other method.
}
you can read more about extensions here.
After reading about good practices to write maintainable and readable code you should do the whole design in interface builder. If you get good understanding of constraints you don't need to write any code to setup design in your view controller. The ViewController.swift file should not be used to fetch-handle data or to setup the UI. It should just be responsible to display and update values which are fetched and get handled in a separate ViewControllerDatasource.swift file. So to sum up, view controller does not have any logic implemented it just handles the show data and the design updates(not setup). I hope i helped you with your question.
I've tried to implement MVVM in a CoreLocation/MapKit project. My main view controller solely derives data from other classes(view models) and displays them. No thinking is done in the view controller.
CoreLocation and MapKit delegate methods are all done in separate classes which pass data to the view controller when the app has been launched.
After the app launches, a model class prepares a path to be drawn on the map when the user starts the process. Even though the path is determined successfully, the path doesn't get drawn since I can't pass data back from model to view-model(MapKit class).
Also even if I could pass data, the view controller already created the map view when the app launched and now it needs to redraw it.
So how can I pass data back from model to view-model and redraw my map view?
P.S. my coding of choice is Swift
You can either use a delegation pattern to notify a delegate class that the model has changed or you can use NSNotification. The latter works better if multiple observers need to know about updates.
In my opinion, however, the MVVM pattern doesn't really work on iOS because it doesn't support UI data binding, so the View-Model doesn't really buy you anything except for added complexity. MVVM originated in the Windows world where there are UI data binding frameworks.
There is a UITableViewCell subclass with a UIButton inside. A web call should be made when the button is pressed.
The question is whether I should set the action in the controller, or can the action be set within the UITableViewCell subclass? Will the second option violate MVC pattern?
The second option will certainly violate MVC pattern. ViewController works like a glue between your models, views and contains all the business logic.
ViewController should receive action then make your api call and put formatted data to your views.
Usually in my project I always try to move networking code into separated set of classes which can handle fetching data from API, transforming from JSON/XML to model objects and formatting them (string date object to NSDate object etc.). Then I can call simple looking method in my ViewController and populate views/tableview cells.
On the other hand,
If you have some time you can look at MVVM which is getting more popular.
There are some links (start with sprynthesis which is AWESOME):
www.sprynthesis.com
objc.io
cocoasamurai
raywenderlich
And some sample apps:
C-41
vinylogue
GroceryList
That helped me to understand MVC more deeply thanks to comparision to MVVM.
Don't be scared with usage of ReactiveCocoa, you can always adopt MVVM without it but it's worth to look at. (It has really steep learning curve and I still feel like an idiot)
Also there is a great article about design patterns with iOS implementation:
raywenderlich design patterns
Well you can delegate the action to the controller from the subclass, that way it'll be handled in the controller, clear, and doesn't violate MVC.
I don't recommend to set the action within the UITableViewCell. What would you do if you need to wait for the answer and the cell needs to be recycle? I will set the action in the controller. This controller should call another class in charge of performing the web call.
I'm new to objective-c and iOS app development, and I have next question:
Is it possible to have one picker view in different views, I mean it should have same data in it and behave equally. Currently i have added 3 picker views, each in different view, and now i have triple copy of same code. So to avoid code duplicating, is there way to create custom view and put this in each of 3 view controllers and just initialize it. Thanks.
Sure. You could even do it all from a separate NSObject inherited class.
Then make that picker class handle all of the picker stuff via its methods.
Then the view controller that wants to use it only has to have an instance of this picker object and it directly calls the needed methods.
That or you can directly create an UIPickerView inherited object and automatically setup its data when it's initialized and use that instead of UIPickerView.
Some quick example code can be found by googling. Here's one: http://iphonedevsdk.com/forum/iphone-sdk-development/46378-subclassing-uipickerview-question.html
If I want to build a generic UI Component (one that will handle its own view and logic, data source,
etc), is it a good practice to subclass UIViewController?
I would say no. But it depends. If your component manages other view controllers or has/will have any kind of logic that's not specific to a view (e.g. navigation logic, business logic etc) , then you should subclass a view controller. Then again that makes it more than an UI component.
Otherwise, you should subclass an UIView, like Apple does with many components, including UITableView (speaking of datasource), GLKView, UICollectionView.
My overly simplistic answer is "no, when building a generic component do not automatically start with a UIViewController subclass". However that alone is not a useful answer and in some cases a UIViewController subclass is exactly the right solution.
Instead let's consider how to decide what your component should be. I think the best way to figure that out is to answer three questions:
What is this component responsible for?
How do you want to interact with it?
What are its dependencies?
In all cases we can try to start as simple as possible and add complexity only when the answers to those questions require it.
Could this component just be a function? No objects, no classes, if all you want to add is some behavior then maybe all we need is a function. If this behavior only applies to specific existing types then maybe we need a category on an existing class.
Not enough to cover what we want to do? Ok, I guess we might be talking about a new type so let's create a class. Can it just be a subclass of NSObject?
Want to display something in a view? Ok, then we at least have a UIView subclass, maybe a UIControl subclass if it is more interactive.
The view needs some data to back it? No problem sounds like we now need two pieces; a view to display data and a data source to provide it. Here the view shouldn't need to know who creates and owns this data source. As long as one was provided to the view we can use it, anything else is outside of the view's area of responsibility. Similarly we might add a delegate to notify some other object of interactions with the view.
If we still haven't covered all of this component's responsibilities then maybe we need yet another piece, something in the controller layer to manage our view. We're still not (yet) talking about a UIViewController though! It's fine to have a "controller" or "service" that is a NSObject subclass. If all this piece needs to do is manage network connections, or map NSFetchedResultController results to our view's data source protocol and update the view, or just provide a convenient implementation of the most common mapping of model objects to the view's data source then a simple "controller" object is still all we need.
Still not enough? Finally we get to the point where we consider providing a UIViewController subclass. Maybe we want to allow users of the component to just present a modal view controller to hand off responsibility for an interaction (send an email, compose a tweet). Maybe there's a common set of default behaviors we want to provide that are tied to view controller life cycle events (UITableViewController flashing scroll bars in -viewDidAppear:).
Build your component from the pieces you need to support the behaviors you want to provide but keep it as small and simple as possible.
Yes, it's good practice in many cases. The iOS SDK contain many examples of UIViewController subclasses. A few of them contain only a small amount of generic behavior and are essentially useless without customization:
GLKViewController
UICollectionViewController
UITableViewController
And some of them provide significant generic behavior but are still mainly containers for your own view controllers:
UINavigationController
UIPageViewController
UISplitViewController
UITabBarController
But most of them are essentially complete packages with little or no need (or ability) to customize their behavior:
ABNewPersonViewController
ABPersonViewController
ABUnknownPersonViewController
EKCalendarChooser
EKEventEditViewController
EKEventViewController
GKAchievementViewController
GKFriendRequestComposeViewController
GKGameCenterViewController
GKLeaderboardViewController
GKMatchmakerViewController
GKTurnBasedMatchmakerViewController
MFMailComposeViewController
MFMessageComposeViewController
MPMediaPickerController
MPMoviePlayerViewController
PKAddPassesViewController
QLPreviewController
SKStoreProductViewController
SLComposeViewController
TWTweetComposeViewController
UIActivityViewController
UIImagePickerController
UIReferenceLibraryViewController
UIVideoEditorController
If you think about what all of these have in common, you may conclude that they all have two things in common:
Each has a specific model (in the MVC sense) that it interacts with, and that model is not specific to your app. The models vary widely (UIVideoEditorController's model is a single video; UIImagePickerController's model is the entire photo library; GKAchievementViewController's model is a database possibly on an Apple server in “the cloud”), in some cases you provide the model (or some properties of the model) up front, and in some cases you receive the model (or a fragment of it) at the end. But in every case, the view controller handles all the interaction between the user and the model with little or no ongoing help from your app.
Each provides its own view hierarchy, with little or no customization required (or even permitted).
In other words, each of these view controllers isn't just the “C” of an MVC pattern. It's the tip of an entire MVC iceberg.
If your component is also an MVC iceberg, then exposing the tip of your iceberg as a UIViewController subclass is quite appropriate.
It depends on the iOS version you used.
A. prior to iOS 5.0, It's not a good practice, and not recommend.
B. start with iOS 5.0, It's just ok.
subclass a view controller for a UI component (UIView), , that means you wanna use the view controller life cycle method, to manage the user interaction and view display procedure, data model etc. So, if the life cycle method can not easily automatic called, the view controller is not that meaningful.
start with iOS 5.0, it's possible to create custom view controller container, so, it's ok to build custom generic ui component with view controller to add as a child view controller.
prior to iOS 5.0. Subclass a UIView with custom delegate protocol is the right way. one other thing is about the code organize. put the all custom delegate method to another custom class, not in the view controller, in the view controller just init a delegate class instance, and set this to the view delegate property.