'self' used before all stored properties are initialized 错误 - @State - 扩展名 - 第二个文件

'self' used before all stored properties are initialized error - @State - extension - second file

我想解耦一些视图。对于这种情况,我在第二个文件的扩展中为带有自定义参数的视图创建了一个初始值设定项。不幸的是,我收到此消息:"'self' 在初始化所有存储的属性之前使用"

如果我将视图和扩展名放在同一个文件中,它就可以工作。但在这种情况下,视图文件需要知道自定义参数。这在另一个项目中可能不需要。

为简单起见,我创建了一个显示问题的示例代码。如果扩展在另一个文件中,我如何在扩展初始化器中初始化 @State 属性 名称?


//  ListCell.swift

import SwiftUI

struct ListCell: View {
    @State var name: String
    var count: Int

    var body: some View {
        HStack {
            Text(name)
            Text(": \(count)")
        }
    }
}

//  ListCell+Ext.swift

import SwiftUI

extension ListCell {
    init(name: String) {
        self.name = name
        count = 0
    }
}

问题是 @State var name: String 实际上是私有值 _name 的糖分,带有一些额外的逻辑。您正在尝试将 String 设置为从状态公开的值(即 State<String>)。如果您尝试在扩展中设置 _name,编译器会抱怨您无法从扩展中访问此私有值。

看来您可以在您的扩展程序中创建一个方便的 init,同时保留默认的,并且只使用它:

//  ListCell.swift

struct ListCell: View {
    @State var name: String
    var count: Int

    var body: some View {
        HStack {
            Text(name)
            Text(": \(count)")
        }
    }
}

//  ListCell+Ext.swift

import SwiftUI

extension ListCell {
    init(name: String) {
        self.init(name: name, count: 0)
    }
}

请注意,Swift 文档确实说只有在没有自定义结构初始化程序时才会生成默认结构初始化程序(“结构类型如果不这样做,则会自动接收成员初始化程序定义任何他们自己的自定义初始值设定项" - under Memberwise Initializers) 但似乎在使用像你的情况这样的扩展时,默认的 init 仍然生成,你可以使用它而不是创建一个......

顺便说一句,一般来说,当您的视图拥有并创建该值时,应该使用 @State,如果它是从上面传递的,您可能实际上应该使用 @Binding 来代替。

这里是@binding的解决方案:


//  ListCell.swift

import SwiftUI

struct ListCell: View {
    @Binding var name: String
    var count: Int

    var body: some View {
        HStack {
            Text(name)
            Text(": \(count)")
        }
    }
}

//  ListCell+Ext.swift

import SwiftUI

extension ListCell {
    init(name: Binding<String>) {
        self.init(name: name, count: 0)
    }
}