'How to show MPMediaItem Artwork in a SwiftUI list?

I try to build a SwiftUI List of all local stored songs on my iPhone. Im using the MediaPlayer Framework of Apple to get the songs and storing them inside an EnvironmentObject for easy access in my SwiftUI view.

Inside my Cell im accessing the image via, but all i get is a white 50x50 block:

Image(uiImage: self.item.artwork!.image(at: CGSize(width: 50, height: 50))!)

Result: https://i.imgur.com/gulvJ8u.png

// EnvironmentObject
class UserData: ObservableObject {

    @Published var allowMusicLibraryAccess: Bool = false
    @Published var songs: [MPMediaItem]

    init() {
        self.songs = [MPMediaItem]()

        self.initAllowMusicLibraryAccess()
    }

    private func initAllowMusicLibraryAccess() -> Void {
        MPMediaLibrary.requestAuthorization { status in
            if status == .authorized {
                DispatchQueue.main.async {
                    self.allowMusicLibraryAccess = true
                    self.songs = MPMediaQuery.songs().items!
                }
            }
        }
    }
}
// List
struct ContentView: View {

    @EnvironmentObject var userData: UserData

    var body: some View {
        ZStack() {
            if self.userData.allowMusicLibraryAccess {
                NavigationView {
                    List {
                        ForEach(self.userData.songs, id: \.persistentID) { song in
                            SongCell(song)
                        }
                    }
                    .navigationBarTitle("Songs")
                }
            } else {
                Text("Music Library Access needed")
            }
        }
    }
}
// Cell
struct SongCell: View {

    let item: MPMediaItem

    init(_ item: MPMediaItem) {
        self.item = item
    }

    var body: some View {

        Button(action: {
            print("clicked \(self.item)")
        }) {
            HStack() {
                if self.item.artwork != nil {
                    Image(uiImage: self.item.artwork!.image(at: CGSize(width: 50, height: 50))!)
                        .resizable()
                        .frame(width: 50, height: 50)
                        .cornerRadius(4)
                }

                VStack(alignment: .leading) {
                    Text(self.item.title ?? "---")

                    Text(self.item.artist ?? "---")
                        .font(.system(.footnote))
                        .opacity(0.7)
                }
            }
        }
        .frame(minWidth: nil, idealWidth: nil, maxWidth: .infinity, minHeight: 55, idealHeight: 55, maxHeight: 55, alignment: .leading)
    }
}


Solution 1:[1]

The solution is to use the .renderingMode() modifier:

Image(uiImage: self.item.artwork!.image(at: CGSize(width: 50, height: 50))!)
    .renderingMode(.original)

Solution 2:[2]

With iOS 15,

We can use

ArtworkImage(artwork: self.item.artwork, width: 250) // Specify the width

Solution 3:[3]

I did figure it out, but it kinda seems like a bug ore some really interesting Initialization behavior I cant explain.

I figured out that moving the Image out of the Cell and directly into the List ForEach fixed that problem. Like I said, I cant explain why this is the case.

// Cell
struct SongCell: View {

    let item: MPMediaItem

    init(_ item: MPMediaItem) {
        self.item = item
    }

    var body: some View {

        Button(action: {
            print("clicked \(self.item)")
        }) {
            VStack(alignment: .leading) {
                Text(self.item.title ?? "---")

                Text(self.item.artist ?? "---")
                    .font(.system(.footnote))
                    .opacity(0.7)
            }
        }
        .frame(minWidth: nil, idealWidth: nil, maxWidth: .infinity, minHeight: 55, idealHeight: 55, maxHeight: 55, alignment: .leading)
    }
}
// List
struct ContentView: View {

    @EnvironmentObject var userData: UserData

    var body: some View {
        ZStack() {
            if self.userData.allowMusicLibraryAccess {
                NavigationView {
                    List {
                        ForEach(self.userData.songs, id: \.persistentID) { song in
                            HStack() {
                                Image(uiImage: song.artwork!.image(at: CGSize(width: 50, height: 50))!)
                                    .resizable()
                                    .frame(width: 50, height: 50)
                                    .cornerRadius(4)
                                SongCell(song)
                            }    
                        } 
                    }
                    .navigationBarTitle("Songs")
                }
            } else {
                Text("Music Library Access needed")
            }
        }
     }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Chorus Audio
Solution 2 Nitish Kumar
Solution 3 KevinP