如何解决.on接收两次发射SwiftUI
我有一个包含Picker的SwiftUI视图。我在Picker的.onReceive内使用Switch语句来调用函数。该函数调用外部API。
问题在于,无论何时初始化视图(即复制数据),该函数都会被调用两次。我不知道为什么两次调用.onReceive。
我认为这可能与在初始化Picker Model并从Picker本身收到另一个通知时调用函数有关,但我不确定如何解决。
这是我的代码:
选择器模型
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
}
}
}
}
任何帮助将不胜感激。
解决方法
很可能每次重新创建ObservedObject
时都会重新创建FilteredMoviesGridView
。每当SwiftUI的运行时认为需要重新创建它时,就会发生这种情况。因此,您的视图创建应该便宜,并且应确保不要意外地重新创建所需的资源。幸运的是,iOS 14等中的SwiftUI使修复此问题变得更加容易。不用@ObservedObject
,而要使用@StateObject
,它会在重新创建视图时使同一实例保持活动状态。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。