我正在尝试将 Binding 传递给我的 VM,它应该是一个过滤器,以便 VM 根据参数传递的过滤来获取对象。
不幸的是,我无法初始化虚拟机,因为我在初始化虚拟机的行中收到错误 'self' used before all Stored Properties are Initialized
self.jobsViewModel = JobsViewModel(jobFilter:$ jobFilter)
struct JobsTab: View {
@ObservedObject var jobsViewModel: JobsViewModel
@ObservedObject var categoriesViewModel: CategoriesViewModel
@StateObject var searchText: SearchText = SearchText()
@State private var isEditing: Bool
@State private var showFilter: Bool
@State private var jobFilter: JobFilter
init() {
self.categoriesViewModel = CategoriesViewModel()
self.jobFilter = JobFilter(category: nil)
self.showFilter = false
self.isEditing = false
self.jobsViewModel = JobsViewModel(jobFilter: $jobFilter)
}
我认为我正在初始化所有变量,并且 self.searchText
不在 init block 中,因为编译器提示它是仅获取属性。
还有其他方法可以做到这一点吗?
谢谢!
编辑:这是我的虚拟机:
class JobsViewModel: ObservableObject {
@Published var isLoading: Bool = false
@Published var jobs: [Jobs] = []
@Binding var jobFilter: JobFilter
init(jobFilter: Binding<JobFilter>) {
_jobFilter = jobFilter
}
...
}
struct JobFilter {
var category: Category?
}
我的想法是将作业过滤器作为 JobsTab 中的一种状态,每次该状态发生变化时,虚拟机都会尝试获取与 JobFilter
匹配的作业
最佳答案
您不应在初始值设定项中创建 @ObservedObject
值。这样做会导致错误,因为每次重新创建 View 时都会创建新实例。 jobsViewModel
和 categoriesViewModel
应作为参数传递给 init
,或者您应该对这些属性使用 @StateObject
.
但无论如何,您实际上问:为什么我们不能在初始化 jobsViewModel
之前使用 $jobFilter
?
让我们从简化示例开始:
struct JobsTab: View {
@State var jobFilter: String
var jobFilterBinding: Binding<String>
init() {
jobFilter = ""
jobFilterBinding = $jobFilter
// ^ 🛑 'self' used before all stored properties are initialized
}
var body: some View { Text("hello") }
}
那么,这是怎么回事?如果我们“去糖化”@State 的使用,将会有所帮助。编译器将 jobFilter
的声明转换为三个属性:
struct JobsTab: View {
private var _jobFilter: State<String>
var jobFilter: String {
get { _jobFilter.wrappedValue }
nonmutating set { _jobFilter.wrappedValue = newValue }
}
var $jobFilter: Binding<String> {
get { _jobFilter.projectedValue }
}
var jobFilterBinding: Binding<String>
init() {
_jobFilter = State<String>(wrappedValue: "")
jobFilterBinding = $jobFilter
// ^ 🛑 'self' used before all stored properties are initialized
}
var body: some View { Text("hello") }
}
现在请注意,$jobFilter
不是存储的属性。它是一个计算属性。因此,访问 $jobFilter
意味着调用它的“getter”,这是 self
上的一个方法。但在 self
完全初始化之前,我们无法调用 self
上的方法。这就是为什么如果我们在初始化所有存储的属性之前尝试使用 $jobFilter
会收到错误。
修复方法是避免使用$jobFilter
。相反,我们可以直接使用_jobFilter.projectedValue
:
struct JobsTab: View {
@State var jobFilter: String
var jobFilterBinding: Binding<String>
init() {
jobFilter = ""
jobFilterBinding = _jobFilter.projectedValue
}
var body: some View { Text("hello") }
}
关于ios - SwiftUI 中的结构体初始化 : 'self' used before all stored properties are initialized,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69071781/