Building Spotify App in Swift 5 & UIKit - Part 13 - Albums (Xcode 12, 2021, Swift 5) - Build App
class AlbumViewController: UIViewController {
private let album: Album
private let collectionView = UICollectionView(
// Custom Collection View
)
private var viewModels = [AlbumCollectionViewCellViewModel]()
...
private func fetchData() {
APICaller.shared.getAlbumDetails(for: album) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let model):
self.viewModels = model.tracks.items.compactMap { track in
return AlbumCollectionViewCellViewModel(name: track.name,
artistName: track.artists.first?.name ?? "-")
}
DispatchQueue.main.async {
self.collectionView.reloadData()
}
break
case .failure(let error):
print(error.localizedDescription)
break
}
}
}
}
extension AlbumViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModels.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: AlbumTrackCollectionViewCell.identifier, for: indexPath) as? AlbumTrackCollectionViewCell else {
return UICollectionViewCell()
}
let viewModel = viewModels[indexPath.row]
cell.configure(with: viewModel)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
guard
kind == UICollectionView.elementKindSectionHeader,
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: PlaylistHeaderCollectionReusableView.identifier, for: indexPath) as? PlaylistHeaderCollectionReusableView else {
return UICollectionReusableView()
}
let headerViewModel = PlaylistHeaderViewViewModel(name: album.name,
ownerName: album.artists.first?.name,
description: "Release Date : \(String.formattedDate(string: album.release_date))",
artworkURL: URL(string: album.images.first?.url ?? ""))
header.configure(with: headerViewModel)
header.delegate = self
return header
}
}
...
extension DateFormatter {
static let dateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd"
return dateFormatter
}()
static let displayDateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .full
return dateFormatter
}()
}
extension String {
static func formattedDate(string: String) -> String {
guard let date = DateFormatter.dateFormatter.date(from: string) else {
return string
}
return DateFormatter.displayDateFormatter.string(from: date)
}
}
...
description: "Release Date : \(String.formattedDate(string: album.release_date))"
...
Date
형식으로 변환 가능한지 guard
캐스팅을 통해 검사하고, 변환 가능하다면 해당 날짜의 표현 방법을 .long
으로 출력특정 데이터의 상세 정보를 읽어온 뒤(즉 API 호출이 완료된 뒤) 해당 정보를 UI에 그릴 때 테이블/컬렉션 뷰 데이터 리로드 함수를 호출해야 한다!