SwiftUI添加Binding属性后出现'self在存储属性初始化前使用'错误
SwiftUI:解决添加focusField后“'self' used before all stored properties are initialized”错误
问题场景
在给SwiftUI的TextInputField视图添加focusField: Binding<Bool>属性后,初始化方法中给model的placeholder、text赋值时触发了'self' used before all stored properties are initialized错误,相关代码片段如下:
struct TextInputField: View { final class Model: ObservableObject { // MARK: Properties @Published var text: String = "" var placeholder: String = "" var currentValue: String = "" var cancellables: Set<AnyCancellable> = Set<AnyCancellable>() // MARK: Initialization init() { self.$text .sink(receiveValue: { value in self.currentValue = value }) .store(in: &cancellables) } } // MARK: Properties private let textFieldPublisher = PassthroughSubject<(String?, TextInputErrorState), Never>() private let output: PassthroughSubject<(name: String?, error: TextInputErrorState), Never> private let textInputType: TextInputType @State private var cancellable = Set<AnyCancellable>() @State private var inputErrorState: TextInputErrorState = .none @State private var isAnimated = false @State private var textBinding: String = "" private var isEditable: Bool = true @FocusState private var isFocused: Bool @ObservedObject var model: TextInputField.Model = TextInputField.Model() @Binding private var focusField: Bool // MARK: Initialization init(title: String, output: PassthroughSubject<(name: String?, error: TextInputErrorState), Never>, inputType: TextInputType = .firstName, currentValue: String = "" , preValue: String = "", isEditable: Bool = true, focusField: Binding<Bool>) { self.textInputType = inputType self.output = output model.placeholder = title // <- 'self' used before all stored properties are initialized if !preValue.isEmpty { model.text = preValue // <- 'self' used before all stored properties are initialized } if !currentValue.isEmpty { model.text = currentValue // <- 'self' used before all stored properties are initialized } self._focusField = focusField self.isEditable = isEditable } }
错误原因
Swift的初始化规则要求:所有存储属性完成初始化后,才能访问self(包括访问self的属性)。当前代码中,你先尝试修改model的属性(这相当于访问self.model),但此时_focusField(@Binding属性的底层存储)还未完成初始化,提前访问self触发了这个错误。
解决方案
步骤1:给Model添加带参数的初始化方法
修改Model的初始化逻辑,支持直接传入placeholder和初始文本,避免后续修改:
final class Model: ObservableObject { // MARK: Properties @Published var text: String = "" var placeholder: String = "" var currentValue: String = "" var cancellables: Set<AnyCancellable> = Set<AnyCancellable>() // MARK: Initialization init(placeholder: String = "", initialText: String = "") { self.placeholder = placeholder self.text = initialText self.currentValue = initialText self.$text .sink(receiveValue: { value in self.currentValue = value }) .store(in: &cancellables) } }
步骤2:调整TextInputField的初始化顺序和model创建方式
首先去掉model属性的默认初始化值,然后在视图初始化时,先完成所有存储属性的初始化,再创建配置好的model实例:
struct TextInputField: View { // ... 其他属性保持不变 ... // 去掉model的默认初始化值 @ObservedObject var model: TextInputField.Model // MARK: Initialization init(title: String, output: PassthroughSubject<(name: String?, error: TextInputErrorState), Never>, inputType: TextInputType = .firstName, currentValue: String = "" , preValue: String = "", isEditable: Bool = true, focusField: Binding<Bool>) { // 先初始化所有存储属性 self.textInputType = inputType self.output = output self._focusField = focusField self.isEditable = isEditable // 确定初始文本优先级:currentValue优先于preValue let initialText = !currentValue.isEmpty ? currentValue : preValue // 创建已配置好的model实例 self.model = TextInputField.Model(placeholder: title, initialText: initialText) } }
核心逻辑说明
通过让Model自己处理初始化配置,我们避免了在视图初始化过程中修改model属性的操作,同时严格遵循Swift的初始化顺序,确保所有存储属性初始化完成后再创建model实例,彻底解决self提前使用的问题。
内容的提问来源于stack exchange,提问作者Bruno
相关产品推荐
相关产品推荐

