@JoeKun,
Wow! Thank you so much for this! It clears up a lot of the confusion I was having with MusicKit. I originally stored the tracks separately since that's how it was done in the official sample app but I see now why it is not needed. The Optional extension is a great idea too and really makes things easier. I am still trying to get my Table to be sortable and then write the contents of the Table to a CSV file and I think the cleaner code and Optional extension will make it easier to figure out. It is amazing how much less code I am writing using SwiftUI with MusicKit versus Apple Music API and AppKit. Thanks again for all of your support!
Post
Replies
Boosts
Views
Activity
Hey @JoeKun,
Thanks so much for responding! I was able some code similar to what you posted, but I used MusicItemCollection() instead. I find it is easier for me to use it as a variable instead of a Type but I am not sure if this is correct. My code is shown below. What is the difference between using "@State var album: Album?" and "@State var album: MusicItemCollection?"
So this question is only part of my overall issue which is getting the results into a SwiftUI Table. When trying to use a Table in your code (based off of the Garden official sample app I get errors such as: "Album.Type cannot conform to RandomAccessCollection" or "Initializer 'init(_:columns:)' requires that 'Album' conform to 'RandomAccessCollection'". I am sure it can be done, I just don't know what steps I am missing. In my code I can make a Table but I have to convert each value into a string at the TableColumn. So what is the best way to do this? How would you make a Table (like the one I have in my code) of all of the album details, or a table of the album's tracks in the code you provided?
Thanks so much!
struct ContentView: View {
@State private var albumDetails = MusicItemCollection<Album>()
@State private var albumTracks = MusicItemCollection<Track>()
@State private var selection = Set<Track.ID>()
@State var sortOrder: [KeyPathComparator<Track>] = [
.init(\.trackNumber, order: SortOrder.forward)
]
var body: some View {
VStack {
HStack {
if let artwork = albumDetails.first?.artwork {
ArtworkImage(artwork, width: 400, height: 400)
}
List(albumDetails, id:\.id) { album in
Text("album id: \(album.id.rawValue)")
.foregroundColor(.secondary)
.padding(2)
Text("title: \(album.title)")
.foregroundColor(.secondary)
.padding(2)
Text("artist: \(album.artistName)")
.foregroundColor(.secondary)
.padding(2)
Text("composer: \(album.artistName)")
.foregroundColor(.secondary)
.padding(2)
Text("total tracks: \(album.trackCount)")
.foregroundColor(.secondary)
.padding(2)
Text("genres: \(album.genreNames.joined(separator: ", "))")
.foregroundColor(.secondary)
.padding(2)
Text("release date: \((album.releaseDate?.formatted(date: .abbreviated, time: .omitted))!)")
.foregroundColor(.secondary)
.padding(2)
Text("record label: \(album.recordLabelName ?? "not available")")
.foregroundColor(.secondary)
.padding(2)
Text("copyright: \(album.copyright ?? "not available")")
.foregroundColor(.secondary)
.padding(2)
Text("upc: \(album.upc ?? "not available")")
.foregroundColor(.secondary)
.padding(2)
}
.font(.system(size: 14))
.onAppear {
albumAPI().requestMusicAuthorization()
async {
self.albumDetails = try await albumAPI().getAlbum()
let firstAlbum = albumDetails.first
self.albumTracks = (firstAlbum?.tracks)!
print(firstAlbum!)
}
}
}
if (albumDetails.first?.editorialNotes?.standard) != nil {
Text("\(albumDetails.first?.editorialNotes?.standard ?? "")")
.font(.system(size: 14))
.foregroundColor(.secondary)
.padding(2)
}
Table(albumTracks, selection: $selection, sortOrder: $sortOrder) {
TableColumn("track") { track in
Text(String(track.trackNumber!))
}
TableColumn("title", value: \.title)
TableColumn("artist", value: \.artistName)
TableColumn("release date") { track in
Text((track.releaseDate?.formatted(date: .abbreviated, time: .omitted))!)
}
TableColumn("duration") { track in
Text(String(track.duration!))
}
TableColumn("isrc") { track in
Text(String(track.isrc!))
}
}
}
}
}
```
You can find the video here: https://wwdctogether.com/wwdc2016/601
a PDF of the content from the video is here: https://docs.huihoo.com/apple/wwdc/2016/601_go_live_with_replaykit.pdf
Anyone? If my question was too long the shorter version is: How do I make an Array of Strings into a String that the SwiftUI Table can use? I am trying to get the genreNames returned from an Apple Music API search into my Swift UI Table that only accepts strings (to my knowledge). Any guesses? Thanks!
I have a follow up question that I bet you know the answer to. Of course no worries if you don't have the time. How would I get [genreNames] into the table? The genreNames that come back are formatted as an Array of Strings. In my data model I had entered the genreNames as [String] as shown here:
struct SongDetails {
var albumName: String
var artistName: String
var artworkURL: String
var composerName: String
var discNumber: Int
var durationInMillis: Int
var genreNames: [String]
var isrc: String
var name: String
var id: String
var releaseDate: String
var trackNumber: Int
but when parsing the JSON when it returns from the API call, it would not let me label the genreNames with .string!
URLSession.shared.dataTask(with: musicRequest) { (data, response, error) in
guard error == nil else { return }
if let json = try? JSON(data: data!) {
let result = (json["data"]).array!
for songDetail in result {
let attributes = songDetail["attributes"]
let song = SongDetails(albumName: attributes["albumName"].string!,
artistName: attributes["artistName"].string!,
artworkURL: attributes["artwork"]["url"].string!,
composerName: attributes["composerName"].string ?? "-",
discNumber: attributes["discNumber"].int!,
durationInMillis: attributes["durationInMillis"].int!,
genreNames: attributes["genreNames"].arrayValue,
isrc: attributes["isrc"].string!,
name: attributes["name"].string!,
id: attributes["playParams"]["id"].string!,
releaseDate: attributes["releaseDate"].string!,
trackNumber: attributes["trackNumber"].int!)
songDetails.append(song)
print(songDetails)
}
so I eventually figured out that it had to be an arrayValue or an Array. So now I have that working but I can't seem to convert the array into a string using join() . I just want a string of the genreNames to put into once table cell.
I also re-wrote everything to use Codable, but got stuck at the east same point. So basically I want to get [genreNames] returned from the JSON to a string such as: Alternative, Indie, Pop. I hope the is enough info for you or else anyone trying to help. This is the last piece I am struggling with.
Thanks!
Figured it out. There are more options for the search results that you can see by using the debugDescription
It worked! Even with me posting the wrong code, it worked!
As far as I check the code, this line is obviously odd:
TableColumn("disc", Int: \.discNumber)
Yes, this is obviously odd and was just something I tried before posting on here. Normally that is not there and the disc number is set up like the rest of them. But your extension worked perfectly! Thanks so much for that!
Just curious but what do you mean by
(I needed to fill many parts missing in your shown code, so some other parts still hidden may be affecting.)
I did not hide any parts of my code. I just forgot to format it after pasting my code here. Is there another reason you say parts were missing? Like am I missing some code that should usually be there but isn't? Except for the issues with Tables, everything works perfectly and now works with Tables thanks to your input.
I really appreciate the response! Thanks again!
I am running OS 12 and I am still getting the "cannot find 'Table' in scope" messages. I am using the latest version of Xcode and making a MacOS app using only SwiftUI. What am I missing here? Thanks
I have been having an issue on macOS with sheet views taking a long time to close. I am new to swiftUI and have been searching for days trying to find a solution for my issue and moving the .sheet modifier to the outermost view bracket instantly solved my issue. Thanks to everyone that contributed to getting this figured out