【问题标题】:.onReceive firing twice | SwiftUI.onReceive 两次射击 | SwiftUI
【发布时间】:2020-09-01 19:37:28
【问题描述】:

我有一个包含 Picker 的 SwiftUI 视图。我在 Picker 的 .onReceive 中使用 Switch 语句来调用函数。该函数调用外部 API。

问题在于,每当初始化视图(即复制数据)时,都会调用该函数两次。我不知道为什么 .onReceive 被调用了两次。

我认为这可能与我初始化 Picker 模型然后从 Picker 本身收到另一个通知时调用的 func 有关,但我不确定如何解决它。

这是我的代码:

选择器模型

import Foundation

class PickerModel: ObservableObject {
    
    @Published var filter = 0
    
    let pickerOptions = ["Popular", "Top Rated"]
    
}

包含选取器的视图:

import SwiftUI

struct FilteredMoviesGridView: View {
    
    @ObservedObject private var filteredMovieVM = FilteredMovieGridViewModel()
    @ObservedObject private var pickerModel = PickerModel()
    
    private var twoColumnGrid = [GridItem(.flexible()), GridItem(.flexible())]
    
    var body: some View {
        
        NavigationView {
            
            VStack {
                
                Picker(selection: $pickerModel.filter, label: Text("Select")) {
                    ForEach(0 ..< pickerModel.pickerOptions.count) {
                        Text(pickerModel.pickerOptions[$0])
                    }
                }.onReceive(pickerModel.$filter) { (value) in
                    switch value {
                    case 0:
                        filteredMovieVM.movies.removeAll()
                        filteredMovieVM.currentPage = 1
                        filteredMovieVM.fetchMovies(filter: "popularity")
                    case 1:
                        filteredMovieVM.movies.removeAll()
                        filteredMovieVM.currentPage = 1
                        filteredMovieVM.fetchMovies(filter: "vote_average")
                    default:
                        filteredMovieVM.movies.removeAll()
                        filteredMovieVM.currentPage = 1
                        filteredMovieVM.fetchMovies(filter: "popularity")
                    }
                }.pickerStyle(SegmentedPickerStyle())
                
                ScrollView {
                    
                    LazyVGrid(columns: twoColumnGrid, spacing: 10) {
                        
                        ForEach(filteredMovieVM.movies, id:\.id) { movie in
                            
                            NavigationLink(destination: MovieDetailView(movie: movie)) {
                                
                                MovieGridItemView(movies: movie)
                                
                            }.buttonStyle(PlainButtonStyle())
                            
                            .onAppear(perform: {
                                if movie == self.filteredMovieVM.movies.last {
                                    
                                    switch pickerModel.filter {
                                    case 0:
                                        self.filteredMovieVM.checkTotalMovies(filter: "popularity")
                                    case 1:
                                        self.filteredMovieVM.checkTotalMovies(filter: "vote_average")
                                    default:
                                        self.filteredMovieVM.checkTotalMovies(filter: "popularity")
                                    }
                                }
                            })
                        }
                    }
                }
                .navigationBarTitle("Movies")
            }
        }.accentColor(.white)
    }
}

包含函数的视图模型:

import Foundation

class FilteredMovieGridViewModel: ObservableObject {
    
    @Published var movies = [Movie]()
    private var filteredMovies = [MovieList]()
   
    var currentPage = 1
    
    func checkTotalMovies(filter: String) {
        
        if filteredMovies.count < 20 {
            fetchMovies(filter: filter)
        }
    }
    
    func fetchMovies(filter: String) {
        
        WebService().getMoviesByFilter(filter: filter, page: currentPage) { movie in
            
            if let movie = movie {
                self.filteredMovies.append(movie)
                for movie in movie.movies {
                    self.movies.append(movie)
                    print(self.movies.count)
                }
            }
        }
        if let totalPages = filteredMovies.first?.totalPages {
            
            if currentPage <= totalPages {
                currentPage += 1
            }
        }
    }
}

任何帮助将不胜感激。

【问题讨论】:

    标签: ios swift xcode swiftui


    【解决方案1】:

    您很可能在重新创建 FilteredMoviesGridView 时重新创建 ObservedObjects。每当 SwiftUI 的运行时认为需要重新创建它时,就会发生这种情况。所以你的视图创建应该很便宜,你应该确保不会意外地重新创建你需要的资源。幸运的是,iOS 14 等中的 SwiftUI 使解决此问题变得更加容易。不要使用@ObservedObject,而是使用@StateObject,这将在重新创建视图时保持同一个实例处于活动状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多