Im updating an app which had many collectionViews embedded inside tableview so I decided to use UICollectionViewCompositionalLayout
instead. I find them very flexible and I was able to design Home page for my app using this layout.
I followed some tutorials which just showed same data types, like Integers in multiple sections or photos app showing photos in different sections. In those tutorials they will use dataSource like this:
var dataSource: UICollectionViewDiffableDataSource<Section, PhotosItem>! = nil
or
var dataSource: UICollectionViewDiffableDataSource<Section, MoviesEntity>!
As my homepage consisted of many types of data, I simply used:
var dataSource: UICollectionViewDiffableDataSource<Section, Int>! = nil
And simply used numberOfSections
, numberOfItemsInSection
and cellForItemAt
methods. I used this approach as my homepage will get data from multiple api's and some sections are static.
In UICollectionView
, I would simply hit an api and update my data model and reload collectionView and do same for different collectionViews handling different data models in same page but now there is only one CollectionView so how do I handle this?
Do I just hit 7-8 API's and reload collectionView everytime? What I would like to do is use snapshot feature of feeding CollectionView with data coming from multiple API's.
This is what I have done to create compositional layout:
func generateLayout() -> UICollectionViewLayout {
let layout = UICollectionViewCompositionalLayout { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
let isWideView = layoutEnvironment.traitCollection.horizontalSizeClass == .regular
let sectionLayoutKind = Section.allCases[sectionIndex]
switch (sectionLayoutKind) {
case .firstSection:
return self.generateFirstLayout(isWide: isWideView)
case .secondSection:
return self.generateCategoriesLayout(isWide: isWideView)
case .services:
return self.generateServicesLayout(isWide: isWideView)
case .spotlight:
return self.generateSpotlightLayout(isWide: isWideView)
case .offers:
return self.generateOffersLayout(isWide: isWideView)
case .reviews:
return self.generateReviewLayout(isWide: isWideView)
case .logo:
return self.generateLogoLayout(isWide: isWideView)
}
}
}
And im simply using these functions to generate sections and adding Dummy items in them:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return Section.allCases.count
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0 :
return 1
case 1 :
return categories.count
case 2 :
return services.count
case 3:
return 2
case 4:
return 5
case 5:
return offers.count
case 6:
return 4
default:
return 10
}
}
So far this is all dummy data and now I want to feed live data and this is not same as what those tutorials did but my sections are different and I could not create something like "PhotosItem" to feed into dataSource method like in those tutorials.
Those tutorials used something like this:
func configureDataSource() {
dataSource = UICollectionViewDiffableDataSource
<Section, AlbumItem>(collectionView: albumsCollectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, albumItem: AlbumItem) -> UICollectionViewCell? in
let sectionType = Section.allCases[indexPath.section]
switch sectionType {
case .featuredAlbums:
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: FeaturedAlbumItemCell.reuseIdentifer,
for: indexPath) as? FeaturedAlbumItemCell else { fatalError("Could not create new cell") }
cell.featuredPhotoURL = albumItem.imageItems[0].thumbnailURL
cell.title = albumItem.albumTitle
cell.totalNumberOfImages = albumItem.imageItems.count
return cell
case .sharedAlbums:
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: SharedAlbumItemCell.reuseIdentifer,
for: indexPath) as? SharedAlbumItemCell else { fatalError("Could not create new cell") }
cell.featuredPhotoURL = albumItem.imageItems[0].thumbnailURL
cell.title = albumItem.albumTitle
return cell
case .myAlbums:
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: AlbumItemCell.reuseIdentifer,
for: indexPath) as? AlbumItemCell else { fatalError("Could not create new cell") }
cell.featuredPhotoURL = albumItem.imageItems[0].thumbnailURL
cell.title = albumItem.albumTitle
return cell
}
}
dataSource.supplementaryViewProvider = { (
collectionView: UICollectionView,
kind: String,
indexPath: IndexPath) -> UICollectionReusableView? in
guard let supplementaryView = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: HeaderView.reuseIdentifier,
for: indexPath) as? HeaderView else { fatalError("Cannot create header view") }
supplementaryView.label.text = Section.allCases[indexPath.section].rawValue
return supplementaryView
}
let snapshot = snapshotForCurrentState()
dataSource.apply(snapshot, animatingDifferences: false)
}
But i don't have one AlbumItem
but like ReviewItem
, OfferItem
and many more. So I was wondering do I stick to my way and just call the api and reload my collectionView?
I have seen many apps that probably have same situation as me. So can anyone help me how to deal with this?
Im using SwiftyJSON
to feed my data into my data models. Just telling this as I have seen in most examples they use Hashable
.