【发布时间】:2021-05-03 05:34:03
【问题描述】:
这里是菜鸟。
我正在制作一个歌词搜索应用程序,它简单地使用一个 API,它接收歌曲名称和艺术家姓名并简单地返回歌词。我基本上有两个问题:
第一个存在:我无法显示包含来自 API 的信息的新工作表。所以我的代码工作如下:从视图中,按下一个按钮,如果用户连接到互联网,调用一个执行整个 API 调用的方法,创建一个 SongDetails 对象,其中包含该歌曲的所有信息(名称,艺术家和歌词)并将其添加到 @Published searchedSongs 数组(之前检查过之前没有搜索过相同的歌曲)。完成后,我希望工作表显示该数组中的歌词。 我的问题是当我想从视图访问 searchedSongs 数组时,应用程序崩溃并出现 IndexOutOfRange 错误,因为它似乎实际上并没有等待 SongDetails 对象在渲染工作表之前完全添加到数组中。我猜这似乎是某种并发问题。有没有办法只在将 SongDetails 对象添加到数组后才显示工作表?我当前的代码是:
HomeView.swift
HStack {
Spacer()
Button(action: {
if(!NetworkMonitor.shared.isConnected) {
self.noConnectionAlert.toggle()
} else {
viewModel.loadApiSongData(songName: songName, artistName: artistName)
self.showingLyricsSheet = true
}
}, label: {
CustomButton(sfSymbolName: "music.note", text: "Search Lyrics!")
})
.alert(isPresented: $noConnectionAlert) {
Alert(title: Text("No internet connection"), message: Text("Oops! It seems you arent connected to the internet. Please connect and try again!"), dismissButton: .default(Text("Got it!")))
}
Spacer()
}
.padding(.top, 20)
.sheet(isPresented: $showingLyricsSheet) {
LyricsView(vm: self.viewModel, songName: songName, artistName: artistName)
}
ViewModel.swift
class ViewModel : ObservableObject {
@Published var searchedSongs = [SongDetails]()
func loadApiSongData(songName: String, artistName: String) {
let rawUrl = "https://api.lyrics.ovh/v1/\(artistName)/\(songName)"
let fixedUrl = rawUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
print("Old url: \(rawUrl)")
print("New url: \(fixedUrl!)")
guard let url = URL(string: fixedUrl!) else {
print("Invalid URL")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let decodedResponse = try? JSONDecoder().decode(Song.self, from: data) {
// we have good data – go back to the main thread
DispatchQueue.main.async {
// update our UI
print("Good. Lyrics:")
if(!self.songAlreadySearched(songName: songName)) {
let song = SongDetails(songName: songName, artistName: artistName, lyrics: decodedResponse.lyrics)
self.searchedSongs.append(song)
}
}
// everything is good, so we can exit
return
}
}
// if we're still here it means there was a problem
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
}.resume()
}
LyricsView.swift
ScrollView {
Text(vm.searchedSongs[0].lyrics)
.foregroundColor(.white)
.multilineTextAlignment(.center)
}
第二个:我很难理解 URLSession 如何处理错误情况。如果出于某种原因(比如我提交“asd”作为歌曲名称,“fds”作为艺术家名称)API 无法检索歌词,我怎么能从视图中知道这一点,甚至无法在第一名,因为根本没有歌词可以显示。
感谢任何帮助。谢谢!
【问题讨论】:
-
您的 URLSession 问题可能应该拆分为自己的问题。当您这样做时,它还可以使用更多细节,例如,如果您指的是诸如 HTTP 错误之类的错误情况,或者您是否从 API 端点获得了某些表示错误的响应(即不同的 JSON 值)。
-
谢谢!我已经提出了一个单独的问题,以防您想快速浏览一下!
标签: swift api rest swiftui urlsession