ios - SwiftUI 中的结构体初始化 : 'self' used before all stored properties are initialized

标签 ios swift swiftui

我正在尝试将 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 时都会创建新实例。 jobsViewModelcategoriesViewModel 应作为参数传递给 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/

相关文章:

ios - 如何在 SwiftUI 中使用 UIViewController 和 UIView?

ios - 在构建 iOS 应用程序时,在范围错误中获取找不到类型 'UIHostingController'

ios - 从 NavigationView 中关闭 SwiftUI 中的父模式

ios - UILongPressGestureRecognizer 不适用于所有 UIButtons

ios - WCSession didReceive 文件不可移动 "No such file or directory"

ios - 如何在 swift 中显示 CGPDFDocument?

ios - 为什么我得到 "generic parameter could not be inferred",通用类型

iOS网站交互(NSURLConnection)设计/模式

ios - 如何在 SwiftUI ListView 中的项目之间创建间距?

ios - AdMob 和 DFP 网络之间的区别?