I got two different Objects Song and Album. I got an AlbumView with a @State var album: Album and I want to reuse that View but pass a Song instead. Is it possible to pass either Album or Song? Otherwise it would also be helpful if I could set Album to nil and then just check in the View whether it has a value.
This is what Album looks like:
struct Album: Identifiable {
let id = UUID()
let name: String
let artist: String
let songs: [AlbumSong]
let releaseDate: Date
let price: Int
let albumImageUrl: String
var unlocked: Bool
}
This is what Song looks like:
struct Song: Identifiable, Codable {
let id = UUID()
let title: String
let duration: TimeInterval
var image: String
let artist: String
let track: String
let price: Int
}
This is my AlbumView:
struct AlbumView: View {
@State var album: Album
var body: some View {
Text("\(album.name)").font(.system(size: 18))
}
}
This would be my idea to solve it with passing one object as nil:
struct AlbumView: View {
@State var album: Album?
@State var song: Song
var body: some View {
if album != nil {
Text("\(album!.name)")
} else {
Text("\(song.name)")
}
}
}
>Solution :
There are multiple ways to do this:
Enum
enum SomeType {
case song(Song)
case album(Album)
}
Then in your View you pass a type to AlbumView & display it like so:
struct AlbumView: View {
@State var type: SomeType
var body: some View {
switch type {
case .album(let album):
Text("\(album.name)")
case .song(let song):
Text("\(song.name)")
}
}
}
You pass the type like so:
AlbumView(type: .album(someAlbum))//for albums
AlbumView(type: .song(someSong))//for songs
Protocol
If you’re using shared property names:
protocol SomeMedia {
var name: String {get set}
//any other shared property
}
struct AlbumView: View {
@State var media: SomeMedia
var body: some View {
Text("\(media.name)")
}
}
Make Album & Song conform to SomeMedia, then you can pass a song or an album as you require!