如何避免 .task SwiftUI View Modifier 每次显示视图时调用我的异步函数?

发布于 2025-01-11 18:15:33 字数 972 浏览 0 评论 0原文

我正在构建一个电影应用程序,其中包含电影列表,一旦按下某个项目,包含该电影详细信息的详细视图就会被推送到导航堆栈上。

因此,我调用一个异步函数,该函数每 10 秒调用一次 API 并更新视图值。我在 .task 视图修饰符中调用它,因此应用程序运行后它就会被调用,这是完美的,问题是一旦用户从详细视图返回到主视图它也会运行。我怎样才能让它只在应用程序运行一次后运行,然后在 10 秒后运行,无论用户是否从一个屏幕导航到另一个屏幕。

API 调用:

func getMovie() async {
    do {
        let movie = try await getMovieFromAPI()
        someMovie = movie
        try await Task.sleep(nanoseconds: 10_000_000_000)
        if !Task.isCancelled { 
           await getMovie()
        
        }
        } catch { 
        // Handle errors
        }
}

ContentView 上的列表:

 List {
            ForEach(viewModel.movies) { movie in
                NavigationLink(destination: MovieDetail(movie: movie, viewModel: viewModel)) {
                    MovieCell(movie: movie, viewModel: viewModel)
                }
            }
        }
 .task {
        await viewModel.getMovie()
    }

基本上我只需要在视图显示后调用 API,然后仅在 10 秒后调用。

Im building a movies app that has a list of movies and once an item is pressed, a detail view with the details of said movie is pushed on the navigation stack.

So im calling an async function that calls an API every 10 seconds and updates View values. Im calling it within a .task view modifier so it gets called as soon as the app runs which is perfect, problem is it is also running once the user returns from the detail view to the home view. How can I make it so it runs only once the app runs and then just after 10 seconds, regardless of wether the user navigates from one screen to another.

API call:

func getMovie() async {
    do {
        let movie = try await getMovieFromAPI()
        someMovie = movie
        try await Task.sleep(nanoseconds: 10_000_000_000)
        if !Task.isCancelled { 
           await getMovie()
        
        }
        } catch { 
        // Handle errors
        }
}

List on ContentView:

 List {
            ForEach(viewModel.movies) { movie in
                NavigationLink(destination: MovieDetail(movie: movie, viewModel: viewModel)) {
                    MovieCell(movie: movie, viewModel: viewModel)
                }
            }
        }
 .task {
        await viewModel.getMovie()
    }

Basically I just need to call an API once the view is shown and then only after 10 seconds.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

抚你发端 2025-01-18 18:15:33

我认为更准确的解决方案是使用计时器。

func getMovie() async {
    do {
        let movie = try await getMovieFromAPI()
        someMovie = movie
    } catch {
        // Handle errors
    }
}

let timer = Timer.publish(every: 10, tolerance: 1, on: .main, in: .common).autoconnect()

List {
   ForEach(viewModel.movies) { movie in
       NavigationLink(
           destination: MovieDetail(movie: movie, viewModel: viewModel)) {
               MovieCell(movie: movie, viewModel: viewModel)
       }
   }
}
.onReceive(timer) { _ in
    Task {
        await viewModel.getMovie()
    }
}

I think more accurate solution will be with using timer.

func getMovie() async {
    do {
        let movie = try await getMovieFromAPI()
        someMovie = movie
    } catch {
        // Handle errors
    }
}

let timer = Timer.publish(every: 10, tolerance: 1, on: .main, in: .common).autoconnect()

List {
   ForEach(viewModel.movies) { movie in
       NavigationLink(
           destination: MovieDetail(movie: movie, viewModel: viewModel)) {
               MovieCell(movie: movie, viewModel: viewModel)
       }
   }
}
.onReceive(timer) { _ in
    Task {
        await viewModel.getMovie()
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文