The Startup
Published in

The Startup

Unifying Table and Collection Views Presentation Logic Within MVVM. Part 2

Hello! Here we are going to create a super simple list using things described in part 1. In the end, we will have this screen done.

Yeah, it doesn’t look cool, but the article is not about design :)

Download starter project:

I have already setup all the needed UI classes. Our plan is to:

  1. Configure view model for our controller
  2. Make our controller conform to some protocols and bind it with the model
  3. Create cells’ models
  4. Create views dependency manager and inject it to the controller

Let’s start.

Open ProfileViewModel.swift file.

Make the model conform to ViewModel protocol. Add setup() method. We will call this method from the view on start. Leave it empty for a while.

Make the model also conform to RxDataSourceProvider protocol and add required collectionData property as constant initialized with an empty array.

Your model now looks like this:

Now let’s switch to ProfileViewController.swift.

Make the view conform to ViewRepresentable protocol. You will have to add model property. Add model variable to the class with type of ProfileViewModel. You will also have to add bindWithModel() method. Add it and leave it empty.

Make the view conform to RxDataSourceRepresentableView. You will have to add three new properties. Add them. Make dataProvider lazy and set it to be your model.

Now in viewDidLoad add two calls:

configureCollectionDataSource() — this will do binding with your datasource provider

model.setup()

Your view class now looks like this.

To render cells on the view we need to create corresponding models and pass them in collectionData subject in our view model.

I will show you how to create one model and you will create others yourself.

Create NamedImageCellModel class and make it conform to CollectionItemViewModel protocol. Add name and imageFilePath properties and corresponding initializer. Your class will look like this:

Now we have to make NamedImageCell class conform to ViewRepresentable protocol and add required properties and methods.

Add model property of type NamedImageCellModel and add bindWithModel method. Now add didSet observer for model property and call setupViewModel method.

In bindWithModel method you set properties for your subviews from the model.

NamedImageCell class head now looks like this:

Do the same activity for other cells in the project. Do not forget to create model for TextHeaderView. Also make sure you follow SomeView-SomeViewModel naming convention.

Now we can fill our collectionData in ProfileViewModel. In setup method add following content:

Here we are creating three sections with different items inside them. Both section model and items models are derivatives from CollectionItemViewModel protocol.

Now open AppLaunchCoordinator.swift and set ProfileViewModel instance to profileController’s model property.

Let’s give it a shot and build and run the project … and make sure there is nothing on screen.

It seems that we forgot something … Of course! Where is our cells dependencies manager? Let’s make one.

Create ProfileViewItemsDependecyManager struct in new file and make it conform to CollectionItemsViewModelDependencyManager protocol. You will be required to add resolveIdentifier(forModelTypeUsingUnusualNaming fullTypeName:) method. Add it and leave it with empty string return, because we don’t have any unusual naming. You will also be required to add dependencies property. Add it as constant. We will now fill the array. Make it look like this:

Here we are telling manager to register TextCell class for TextCell reuse identifier without any nib, register NamedImageCell class for NamedImageCell reuse identifier without any nib, register AttributeCell class for AttributeCell reuse identifier without any nib and register TextHeaderView class for header view with TextHeaderView reuse identifier.

Open AppLaunchCoordinator and inject our new manager to profileController.

Build and run the project.

Oh nice! You see some content, but its layout is broken. Let’s fix it in our profile controller. Add following extension:

Of course we could make cells self-sizable, but that’s not the topic of the article. Also you can set corresponding properties to the layout in the initializer instead of making this extension.

Build and run one more time. And see the result.

Now revise your controller’s content. Do you see any data source related method? Do you see if clauses for different cells maybe?

No. And you will never see them again.

Note that there is a lot more than I told about in the article. I’ve only described some basic usage.

Final project is available here:

Hope you loved this!

--

--

--

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +756K followers.

Recommended from Medium

iOS 14.5 could be a concern for Facebook — Here’s why

How to Use ‘UIViewRepresentable’ With SwiftUI

Bottom Sheet Presentation in SwiftUI

Zeon Jailbreak for iOS 14.3

Opacity Animation in SwiftUI

Implementing Tree Data Structure in Swift

Flutter: Emerging Dominance In The Cross-platform Market

New in SwiftUI 4: NavigationSplitView

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Isa Aliev

Isa Aliev

iOS-Developer from Russia

More from Medium

Mobile CI — Gitlab CI

Making http request without crying in Swift 5 😎 — Part 1

Retain Cycle… Cause And Solution

Deploy iOS Application to AppCenter via Github Actions (Manual Code SignIn)