在另一个函数中调用async func并更新UI



这是我的异步函数类:

class MoviesViewModel: ObservableObject {
@Published var topRated: [Movie] = []
@Published var popular: [Movie] = []
@Published var upcoming: [Movie] = []
func getUpcomingMovies() {
if let movies = getMovies(path: "upcoming") {
DispatchQueue.main.async {
self.upcoming = movies
}
}
}
func getPopularMovies() {
if let movies = getMovies(path: "popular") {
DispatchQueue.main.async {
self.popular = movies
}
}
}
func getTopRatedMovies() {
DispatchQueue.main.async {
if let movies = self.getMovies(path: "top_rated") {
self.topRated = movies
}
}
}
func getMovies(path: String) -> [Movie]? {
var movies: [Movie]?
let urlString = "https://api.themoviedb.org/3/movie/(path)?api_key=(apiKey)&language=en-US&page=1"

guard let url = URL(string: urlString) else { return [] }
let session = URLSession.shared

let dataTask = session.dataTask(with: url, completionHandler: { data, _, error in
if error != nil {
print(error)
}
do {
if let safeData = data {
let decodedData = try JSONDecoder().decode(NowPlaying.self, from: safeData)

DispatchQueue.main.async {
movies = decodedData.results
}
}
}
catch {
print(error)
}

})
dataTask.resume()
return movies
}

}

当我在getMovies函数中打印电影时,我可以毫无问题地从api中获取电影。但是,UI不会自行更新。我使用了DispatchQueue.main.async函数,但它并没有解决我的问题。在这种情况下我该怎么办?

dataTask异步工作。您的代码甚至在异步任务开始之前就返回了nil。您必须使用完成处理程序,如Swift函数中从异步调用返回数据中所述。

我强烈建议在这种情况下使用async/await。您可以去掉很多样板代码,并且不需要关心线程的调度。

@MainActor
class MoviesViewModel: ObservableObject {
@Published var topRated: [Movie] = []
@Published var popular: [Movie] = []
@Published var upcoming: [Movie] = []

func getUpcomingMovies() async throws {
self.upcoming = try await getMovies(path: "upcoming")
}

func getPopularMovies() async throws  {
self.popular = try await getMovies(path: "popular")
}

func getTopRatedMovies() async throws  {
self.topRated = try await getMovies(path: "top_rated")
}

func getMovies(path: String) async throws -> [Movie] {
let urlString = "https://api.themoviedb.org/3/movie/(path)?api_key=(apiKey)&language=en-US&page=1"

guard let url = URL(string: urlString) else { throw URLError(.badURL) }

let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(NowPlaying.self, from: data).results
}
}

最新更新