Bartlomiej Guminiak
Posted on September 3, 2019
MVVM design architecture
is getting increasingly popular in iOS development
and it is my favourite considering last months ❤️
Recently I've completed implementing relaxing dribbble shot of Ela Kumela 🧘♂️
Today, I would like to share with you details on how did I solve song management functionality in MVVM
world. I hope you will find it useful and find inspiration in your beloved iOS development 🤠
Below you can see iPhone simulator recording from the music player
Player demo |
---|
Model
As you can see there are two screen kinds:
- picking
- listening
and, in total, four different modes of the SongCell:
.picking(.unselected) | .picking(.selected) | .listening(.playable) | .listening(.playing) |
---|---|---|---|
Combinig them together we will build structure such below:
enum Picking: Equatable {
case selected, unselected
}
enum Listening: Equatable {
case playable, playing, hidden
}
enum SongMode: Equatable {
case picking(Picking)
case listening(Listening)
}
There is one additional mode of .listening(.hidden)
. In the listening mode all unselected cells get invisible.
ViewModel
In MVVM world every subview has its corresponding viewModel. In our case every SongCell has its SongViewModel. Take a look at its interface:
protocol SongViewModeling: class {
var title: String { get }
var subtitle: String { get }
var time: String { get }
var songMode: SongMode { get set } // 1
var songModeHandler: SongModeHandling { get } //2
}
There are two interesting properties we should take closer look at:
1
- we will use that model for cell configuration
2
- SongModeHandling is an observer pattern protocol. When updating the songMode, songModeHandler should emit the current mode. We will use it for updating visible cell states. Remember to unsubscribe from it when reusing the cell ☝️
Binding viewModels with cells
The last part that left is binding songViewModels with its corresponding songCells. We will implement that logic in MeditationViewController as it already is a delegate and data source of tableView. Below there is a simplified MVVM architecture flow:
Simplified MVVM architecture flow |
---|
1
- MeditationViewController updates its MeditationViewModel about view life cycle and UI actions
2
- MeditationViewModel updates MeditationViewController with songViewModels
3
- MeditationViewController binds songViewModels with songCells
func configure(cell: SongViewCell, with viewModel: SongViewModeling) {
cell.interactiveView.songView.titleLabel.text = viewModel.title
cell.interactiveView.songView.subtitleLabel.text = viewModel.subtitle
cell.interactiveView.songView.timeLabel.text = viewModel.time
cell.update(mode: viewModel.songMode, animated: false)
cell.disposable = viewModel.songModeHandler.addHandler(target: cell,
handler: SongViewCell.update)
}
4
- MeditationViewModel manages business logic. It listens to ActionViewModel events and delegates work to MusicPlayer
5
- MusicPlayer contains aggregate methods for altering modes of song ViewModels - stateless entity
Summary
In MVVM architecture we name both ViewControllers and Views as View and it should not have any business logic but only listens to its ViewModel orders. In our meditation example the View (MeditationViewController) is completely without business logic. It has only view logic such building subviews and configuring them with child viewModels (songViewModels)
This way all the business logic can be extracted to ViewModel (MeditationViewModel) and its helpers that make the code readable and divided into single responsibility entities:
- songViewModels manager MusicPlayer
- screen state operator MeditationScreenStateOperator
For more details see meditaion-ios-demo
Enjoy! ❤️
License
Copyright © 2019 EL Passion
Posted on September 3, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.