MVVM(Model-View-ViewModel) with Swift application 3/3

This is the last post of creating an MVVM (Model-View-ViewModel) application with Swift series. In the first and second part we went through the basic principles of MVVM, covered data binding pattern and also handled presenting errors to the user. At the end of the second post we were able to download and present friend data to the user using tableview. This last post adds functionality to the application. We’ll create, update and delete users from the backend and we will also pass a ViewModel into View when we are updating friends information.

As you might have guessed, we will continue to use the FriendService built in the first post: Server-side Swift, how to setup a backend. You can either set up the backend at your localhost by following the instructions in the post, or you can use the service I have running on Heroku. For example to list all friends you should use http-get with this url: http://friendservice.herokuapp.com/listFriend.

You can download the complete source code to the mobile client here: https://github.com/JussiSuojanen/friends. It contains complete code for the Friend application. But without further ado let’s get to it!

Adding a new Friend

Open the main storyboard, add a new ViewController to the project and make it look similar to the one in the picture below:

ViewModel for AddFriendViewController is created in prepareForSeque

Now add a new file inside the ViewModel folder, name it FriendViewModel and put the code below in it:

FriendViewController is going to be used both for adding and updating friend information. By defining a protocol you can have two different ViewModels conforming that protocol and ViewController only needs FriendViewModel as a reference type. The ViewModels share all the other variables except for the title and for the submitFriend function which will have different implementations based on the task at hand. Next continue to implement the AddFriendViewModel class by adding the following code below the FriendViewModel:

FriendViewModel code

Title variable works as a title for our view and this case it returns “Add friend”. The rest of the string variables are pretty self explanatory except for the didSet part. Every time a user inputs data to the form a validation function is called. Inside validateInput function all the strings, that can be modified by the user, are checked that it contains more than 1 character and then set the validInputData variable accordingly. If the value is different than the previous one, FriendViewController is triggered inside the didSet block to update submission button state. This will prevent the user from sending invalid data to the backend. One thing to mention here is that you can define a new rule for the validInput data, if you want to be more specific about what information the fields should have. For now this example will only use the simple check that the fields should have a string that contains more than one character.

 

Other than those there is also showLoadingHud, which is used to indicate that information is being sent to backend, navigateBack function which triggers returning to the previous view and also onShowError function which will present errorDialog to the user. ViewModel also has its own instance of AppServerClient which handles networking and the actual data sending happens in the submitFriend function. At the end of the file there is a private extension for mapping error codes to messages that can be shown to user. The code should look pretty familiar because all the basic concepts here are pretty much repetitions of similar things in the FriendTableViewViewModel. The only new thing is the SingleButtonAlert which will be covered next.

SingleButtonAlert

SingleButtonAlert is a helper struct for presenting alert dialog with a single button. With this helper struct, dialog creation can be handled mostly in ViewModel side. Create a new file called Alert inside the Helpers folder and put the code below in it:

AlertAction defines button title and handler. Button title defines the title for the button and handler is a function which will be called after user presses that button. SingleButtonAlert defines title and message for the alert dialog and it also has the AlertAction as the button title and tap handler.

 

Now open the FriendViewModel again and look the failure block inside submitFriend function. Here you create a new SingleAlertAction with correct texts and also define response block for the button. Now when user presses the “OK” button in the dialog, the code block defined in the failure will be called. This case the error dialog only dismisses itself and no further actions are needed. Here “Ok pressed!” is printed for demonstration. If you’d need to react for the button press, for example by reloading data etc, you’d put the reload function call here.

 

Send a new friend to the backend

Open AppServerClient and implement the following code:

Again this all looks very familiar since you have done it once before. The biggest difference here is the EmptyResult which is used because server doesn’t send any JSON as a response from a successful post. Other than that, in the beginning of the postFriend function dictionary containing keys and values are created for the friend and it is passed as a parameter in the Alamofire request. One thing to notice here is that the method in the call is defined as “post” when previously when you were listing the friends method, it was defined as “get”.

 

Now all that is left to get this code to compile, is to add that EmptyResult enumeration. Open Result file in the Helpers folder and add the following code to it:

EmptyResult is almost the same as the Result enum defined before, but now success case doesn’t have any parameter defined. Now that the ViewModel side is ready it is time to move on to the view side.

 

FriendViewController

FriendViewController works as view for the friend creation part of the application. Create a new file inside the ViewController folder and put the code below inside it:

At the beginning of the file all the outlets for the textfields and the button are defined. The most interesting thing here is once again the didSet blocks. When outlets are created FriendViewController is set as the delegate for the textFields. Also a textFieldDidChange function is defined for all the textFields so that every time user types in something, the ViewController will catch the change. As you can see inside the textFieldDidChange functions the ViewModel variables are always updated according to the input provided by the user.

 

When you look at the bottom of the file you’ll see an extension which conforms to UITextFieldDelegate. Here the activeTextField is updated according to active field. This allows you to dismiss the keyboard, when it is open and user taps the screen outside the textFields. Next focus on the other extension which is just above the UITextFieldDelegate. You’ll see that the actions for both the rootViewTapped and the button press are handled here. Open storyboard and connect the UIButton action to the submitButtonTapped (which will then call viewModels submitFriend function), and then create the UITabGestureRecognizer according to the image below.

 

Add UITabGestureRecognizer

You can just drag and drop the UITabGestureRecognizer inside the ViewController and then set the outlet, action and delegate according to the image. Now every time user taps outside the fields, resignFirstResponder is called for the active textField and keyboard is dismissed. Now that the view is properly set up and all the actions and outlets are connected (you might want to double check if you have doubts), its time to focus on the connection between the ViewModel and the View.

Connecting the ViewModel to the View

ViewModel type is defined as the FriendViewModel protocol. This is because the same ViewController will also be used for updating friend information. At that point a new ViewModel is defined called UpdateFriendViewModel which conforms to the same FriendViewModel protocol. ViewModel is always created when we trigger a segue to open FriendViewController, and set to the FriendViewController ViewModel.

 

BindViewModel function looks pretty familiar, but there are few things that needs further explanation. At first, if friend text are available, the values are updated to the UI. This actually happens only if friend information is being updated, so the strings are always cleared at this state of the implementation. Also the title for the view is set according to title set inside the ViewModel.

 

ShowLoadingHud part is familiar from the previous view implementation, it only presents and hides the hud according to network request activity. Also updateSubmitButtonState is pretty self explanatory, submitButton state is set inside it, but the last two code blocks need a little bit more thorough explanation.

Navigate back

Navigate back is function, which is called from the ViewModel when a new user is successfully created, and after that user is returned straight back to the list of friends. Inside the function, navigationController pops the current viewController from the view stack, which returns the user to the previous view. Before the view is dismissed, updateFriends function is called. You don’t want friend list to be updated every time you return back to it, as it is implemented at the moment (viewWillAppear is calling getFriends), so you need something to inform that there is new information available in the backend. When the segue for opening the FriendViewController is triggered, updateFriends function is defined, which then triggers the friend data updating. That will be covered right after the friend adding is completed, so you have to wait a little bit longer.

Presenting error dialog to the user

Last thing inside the bindViewModel function is onShowError function. Here you create an UIAlertController and use the variables from the SingleButtonAlert which is created in the viewModel. You get the title and message from the SingleButtonAlerts title and message variables, and for the button you can set the AlertActions title and handler. This way it is easy to handle the button press inside ViewModel.

 

Things are looking great! Now that AddFriendViewModel and FriendViewController is completed, it is time to make the changes for FriendTableViewController.

 

Open the AddFriendView

Open the storyboard file again and if you haven’t done so, add the barButtonItem to the top right corner of the FriendTableViewController:

ViewModel for FriendViewController is created in prepareForSeque

Next add a new Segue from the button to the FriendViewController by holding ctlr, then drag the mouse cursor over to the FriendViewController and select show as the type for the segue. Inside the attributes inspector give this segue an identifier called “friendsToAddFriend”. Now open FriendTableViewController file again and put the code below in it:

Inside the prepare for segue function (which is called by the system every time a segue is triggered), you first check that the identifier for the segue is the one defined a moment ago. After that make sure that destination view controller is the type of FriendViewController and if that is the case create the AddFriendViewModel and set it as the ViewModel for the FriendViewController. Here you also define the updateFriends function. Set it as closure, remember to add a capture list and set self reference as weak, and define that getFriends is called when the block is run. Last thing to do is to remove the getFriends call from the viewWillAppear function, and now friend data is only updated if new data is actually available. You actually should not have anything inside the viewWillAppear function so the implementation can be removed completely.

 

Now you can run and test the code. Open the AddFriendView and type some information to the form. You can see the submit button active only after all the fields are correctly filled, and after you press the submit button the information is sent to server. The app returns to the previous view after request is completed, which then updates the friend information, that now also holds the information you just added. Now that’s what you can call a successful first run! Now it’s the time when you can give your self a small tap in your shoulder for all the good work you have done so far. You might also want to call a friend and explain to her how exceptionally good person you are!

 

Updating a friend

Now that you are able to add new friends, next step is to update friend information. Create a file called UpdateFriendViewModel and put the code below in it:

UpdateFriendViewModel conforms to FriendViewModel protocol so most of the code here is very familiar. It has all the same strings, validInputData and functions as the AddFriendViewModel. The only difference here is actually the title implementation which returns “Update friend” string this time, and submitFriend function which also has a different implementation, and that now you store an instance of Friend model. Friend model is here because you need to identify the user which information is updated. Inside the submitFriend function you won’t call postFriend function this time, but instead a new function in AppServerClient called patchFriend is used. Since all the other things here are more or less familiar, next you will implement the patchFriend function.

Send friend information to backend

Open AppServerClient and put the code below in it:

Most of the code here is repetition of previous lines you have written. You create a dictionary containing friend information, handle response and call the completion block with correct value. One thing to point out here is that in order to identify the user you will pass the id as parameter in the url, not inside the parameter object, and that the http-method used here is patch.

 

Now because all the other stuff inside UpdateFriendViewModel is familiar you can move straight to FriendViewController to activate friend updating, when user selects a cell inside the tableview.

Opening update friend view

Open the main.storyboard again and ctrl drag cursor from a cell to the FriendViewController. Once again select “Show” as the segue type, and set the identifier as “friendToUpdateFriend” in the attribute inspector. Now open FriendTableViewController and add the following code inside the prepare for segue:

Now there is a new block of code for handling the segue you just created. First check that the identifier is a match. Then check that destination ViewController is FriendViewController. Next check which TableViewCell cell was pressed and then get the matching ViewModel from the friendCell array. Since friendCells holds instances of FriendTableViewCellType use switch to go through the types. The only thing that can be used here is the normal cellViewModels, so the empty and error types needs no operations. If the selected cell contains normal cell, create a new UpdateFriendViewModel and use the viewModel.friendItem as the parameter in the initializer. Next just as it was the case with AddFriendViewModel, define the udpateFriends function so that data is updated when friend data is updated.

 

That is actually all you need to do. Since the FriendViewController is already set up for the FriendViewModel protocol, and the bindViewModel function is called, all is set inside the FriendViewController. Now that was quick! Wasn’t it? Now you can build and run the application, update any friends information, and you should also hear the applauses at the back of your mind while testing this new functionality!

 

Deleting a friend

The application is almost ready and the last thing to do is to add deleting functionality. While it is really encouraged to always forgive when some one has done wrong to you, there is still some lines that cannot be crossed. Just incase, make sure that the application is ready for a situation that you need to remove someone from your circle of trust.

 

Open FriendsTableViewController and add the following two functions inside the FriendsTableView extension block at the bottom of the file:

The first new delegate function canEdiRowAt tells the TableView that it is ok for the user to edit the rows and the second one, editingStyle defines how to react to different editing styles. Inside the editingStyle function, check first that the style is delete and then call a function named deleteFriend which takes the editing row index as parameter. Now open up FriendTableViewViewModel and next you will implement the deleting function.

At the beginning of the function you’ll first get the correct friend which is being deleted using the index. Next, as it was the case with the prepareForSegue function, use switch statement to check the type of the friendCell. You only want to call AppServers delete function when the row that is affected is a normal one and also holds a viewModel, so define normal case so that the AppServerClient is called inside that block. You have to also define a default case so that every case is handled in the switch statement, although the default case will never be called with the current implementation (all other cells isUserInteractionEnabled is set to false).

 

Inside the normal case call the deleteFriend function, which will be implemented in a second. Give it friend id as parameter so that backend can identify which friend needs to be deleted. After that just handle the result using another switch statement. Inside success block call getFriends to get the latest data from the backend which will then update it to the UI. In the failure case construct and error and present it the same way that was done a moment ago with FriendViewController. You also need to add definition for the onShowError function, which is exactly the same as in the AddFriendViewModel:

And also remember to add the handler inside the FriendsTableViewControllers bindViewModel like this:

Now there is still one thing that needs to implemented inside the FriendsTableViewViewModel before you can proceed to AppServerClient to add the deletion function. Add the following extension for error handling at the bottom of the file:

Now also the deletion http-error codes are transformed to human readable form which can be presented to the user.

Deleting friend from the server

Now open the AppServerClient to implement the last method that is needed in the AppServerClient: deleteFriend.

The request is almost identical to the last one, with the exception that there is no parameters and that method is delete. Ones again the userId is used to identify the user in the server. Now that the delete function is also implemented everything is ready! Run the application and swipe left from one of the cells:

When the cell is swiped left the delete button is shown in the right side of the cell and pressing that will start the deletion of the selected friend. As you see in the picture above Dolph Lungren is the one being deleted for showing such a weak character in the first expendable movie.

 

Application is finished

And thats it! Now the application is ready. Now it can create, update, delete and list friends. If you have hanged with me this long I really want to thank for reading it through. I also hope that you have learned something and if you have liked the blog, you can subscribe to the mailing list or follow me on twitter to get frequent updates.

 

I know that unit testing is mentioned many times in the blog post and so far you have not seen a single test written. The MVVM series started get bigger and bigger so I didn’t want to add fourth post in it. But no worries, the blog post is available and you can check it here: unit testing view models

This article has 6 comments

  1. Filip M. Reply

    Read your articles about MVVM and it was great help to me to understand this topic and implement into my project. There is a lot of resources on other third part libraries but none of them explain core concept of MVVM explained in code. This is a 5 star article. Thank you a lot for this awesome blog, keep up with good work 🙂 cheers

    • Jimmy Reply

      Thanks Filip!

      I am glad that you liked the post and that I was able to help you 🙂 cheers

  2. Sergey Reply

    Thanks. MVVM Like MVP, but different between theirs that in MVP all logic we holding in Presenter, and UI implementation in ViewController. In MVVM logic and UI implementation we holding in ViewModel.

    If I understand right.

    • Jimmy Reply

      Hi Sergey,

      I haven’t used MVP in any of my projects but what I have understood that is pretty much how it works.

      MVVM is very close to MVP. ViewModel holds all the business logic and ViewController acts as a View and implements the UI. As I said, I am not that familiar with MVP so I cannot tell you what are the fundamental differences between the two, other than the 2 letters in the name 🙂

Leave a Comment

Your email address will not be published. Required fields are marked *