Reputation: 24341
I’m working on an app that has the following View Hierarachy:
ViewController
-> contains UITableView
-> contains CustomTableViewCell
-> contains UICollectionView
-> contains CustomCollectionViewCell
Now I've created a ViewModel
corresponding to the ViewController
. The ViewModel
contains the model objects for CustomTableViewCells
, i.e. the number of CustomTableViewCells
to show and what content to show in each CustomTableViewCell
.
class ViewModel
{
//MARK: Private Properties
private var libraries = [Library](){
didSet{
self.reloadTableViewClosure?()
}
}
//MARK: Internal Properties
var reloadTableViewClosure: (()->())?
var numberOfLibraries: Int{
return self.libraries.count
}
//MARK: Internal Methods
func getLibrary(at indexPath: IndexPath) -> Library
{
return self.libraries[indexPath.row]
}
//MARK: Initializer
init()
{
self.fetchLibraryList()
}
//MARK: Private Methods
private func fetchLibraryList()
{
if let path = Bundle.main.path(forResource: "LibraryList", ofType: "json")
{
if let libraryList = try? JSONDecoder().decode([Library].self, from: Data(contentsOf: URL(fileURLWithPath: path)))
{
self.libraries = libraryList
}
}
}
}
I want to know how should I handle UICollectionView
with MVVM?
Should I make the main ViewController
the delegate & dataSource for both UITableView
& UICollectionViews
?
Where should I keep the model objects for CustomCollectionViewCells
? In the same ViewModel
or should I make a different one?
Upvotes: 1
Views: 1504
Reputation: 15258
What i can figure out in this situation is as below,
You should create 3 ViewModels
ViewController
CustomTableViewCellView
CustomCollectionViewCellView
And here is how your ViewModels
should look like,
class ViewModel
{
private var cellVMs = [CustomTableViewCellViewModel] = []
var reloadTableViewClosure: (()->())?
var numberOfLibraries: Int {
return self.cellVMs.count
}
func getLibraryCellVM(at indexPath: IndexPath) -> CustomTableViewCellViewModel
{
return self.cellVMs[indexPath.row]
}
//MARK: Initializer
init()
{
self.fetchLibraryList()
}
//MARK: Private Methods
private func fetchLibraryList()
{
if let path = Bundle.main.path(forResource: "LibraryList", ofType: "json")
{
if let libraryList = try? JSONDecoder().decode([Library].self, from: Data(contentsOf: URL(fileURLWithPath: path)))
{
libraryList.forEach({
cellVMs.append(CustomTableViewCellViewModel(library: $0))
})
self.reloadTableViewClosure?()
}
}
}
}
Your CustomTableViewCellViewModel
will look like this,
class CustomTableViewCellViewModel {
var booksVMs: [CustomCollectionViewCellViewModel] = []
var library: Library!
init(library: Library) {
self.library = library
// Initialize booksVMs
library.books.forEach({
booksVMs.append(CustomCollectionViewCellViewModel.init(book: $0))
})
}
var numberOfBooks: Int {
self.booksVMs.count
}
func bookViewModel(at indexPath: IndexPath) -> CustomCollectionViewCellViewModel {
return self.booksVMs[indexPath.row]
}
}
and finally CustomCollectionViewCellViewModel
will look like this,
class CustomCollectionViewCellViewModel {
var book: Book!
init(book: Book) {
self.book = book
}
var bookName: String? {
return self.book.name
}
}
Upvotes: 3