swift 当变量第一次在它自己的初始化中使用时,如何清除“变量...在初始化之前使用”错误?

rur96b6h  于 2023-02-28  发布在  Swift
关注(0)|答案(2)|浏览(129)

**背景:**我正在使用Core Data处理应用用户设置的永久存储。我的设置之一是Color值,我正在将其转换为RGB值,并将其存储为由Core Data管理的InitialsImageColor类型对象的属性。Color是使用ColorPickerForm视图中选择的。
**问题:**我在视图的init()声明中初始化了一个变量imageColor。编译器抛出一个错误,称“Variable 'self.imageColor' used before been initialize”5次。为了清楚起见,以下是相关的代码部分和注解:

struct SettingsView: View {
    // Access the managed object context for saving changes to Core Data
    @Environment(\.managedObjectContext) var moc

    // Load stored InitialsImageColor objects from Core Data
    @FetchRequest(sortDescriptors: []) var colorSetting: FetchedResults<InitialsImageColor>
    
    // A Color variable for the ColorPicker View to bind to
    @State private var imageColor: Color

    // A String variable for the Form View's .searchable modifier to bind to
    @State private var searchText: String = ""
    
    // A Bool variable to change to make the .sheet containing SettingsView to disappear
    @Binding var showSettings: Bool
    
    // An initializer to set the starting value for the ColorPicker View to use
    init() {
        imageColor = Color(                        // This line throws error
            red: colorSetting.first?.r ?? 255.0,   // This line throws error
            green: colorSetting.first?.g ?? 255.0, // This line throws error
            blue: colorSetting.first?.b ?? 255.0,  // This line throws error
            opacity: colorSetting.first?.a ?? 1.0  // This line throws error
        )
    }

1.这怎么可能呢?变量的第一次使用是在初始化器中。这个错误不应该发生。
1.我该怎么做才能修好它?
最初,我尝试在imageColor的声明中初始化它,但当然没有成功,因为它使用另一个变量来得出它的值,并且作用域在视图的body之外。我将它放在init()声明中来解决这个问题,然后发生了这种情况。

dw1jzc5e

dw1jzc5e1#

这里你的代码有几个问题。首先,imageColor有一个a @State属性 Package 器,这意味着你实际上想这样初始化它:

_imageColor = State(initialValue: Color(red: 1, green: 1, blue: 1)

不过,您也可以在声明中轻松地这样写:

// A Color variable for the ColorPicker View to bind to
@State private var imageColor = Color(red: 1, green: 1, blue: 1)

因为第二个问题是,你期望fetch请求在init期间发生。事实并非如此。你可以也应该期望SwiftUI视图被初始化和销毁很多次,超出你的控制范围。记住这个原理,你可以看到在初始化时执行fetch请求是没有意义的。它将在视图的body被求值时执行。
更好的解决方案可能是将颜色定义为自定义绑定,而不是单独的状态变量,然后您可以将其传递给其他视图:

private var imageColor: Binding<Color> {
    Binding<Color>(
        get: { 
            Color(                        
                red: colorSetting.first?.r ?? 255.0, 
                green: colorSetting.first?.g ?? 255.0,
                blue: colorSetting.first?.b ?? 255.0, 
                opacity: colorSetting.first?.a ?? 1.0 
            )
        },
        set: {
            // Write back to your data object
        }
    )
}

(我在这里留下了你的255个值,因为我刚刚从问题中复制过来)

f0brbegy

f0brbegy2#

我找到了一个变通方法,经过思考,我意识到实际上并不需要将imageColor初始化到持久化数据对象(我一直在考虑使用与涉及UserDefaults的旧尝试相关的范例),所以我在声明中初始化了它,如下所示:
@State private var imageColor: Color = .white
然后我仅仅更新了初始化器中的值(根本没有改变我的代码**[但请参见编辑]**)。
然而,这产生了类似的错误,它现在告诉我另一个变量@Binding var showSettings: Bool正在做同样的事情:“变量'self.showSettings'在初始化之前使用”。我也找到了一个解决方法。我没有使用它来消除.sheet,而是简单地使用dismiss关键帧声明了一个环境变量,如下所示:
@Environment(\.dismiss) var dismiss
然后我用我的Done按钮调用它,而不是设置showSettings = false

**EDIT:**构建并打开视图后,我收到以下警告:“访问StateObject的对象,而没有安装在视图上。这将每次创建一个新示例。”它的行为与警告指示的一样。所以我删除了初始化器,并将其代码放在Form视图的.onAppear修饰符中(我还将nil合并更改为强制展开,因为我在运行属性设置代码之前使用了if块来计算!colorSetting.isEmpty)。

相关问题