SwiftUI:从另一个初始化程序调用它时,如何使我的闭包 return 'Content' 而不是 'some View'?

SwiftUI: How do I make my closure return 'Content' instead of 'some View' when calling it from another initialiser?

我目前正在学习SwiftUI,我运行陷入了一个问题。

在下面的代码中,我有两个初始化器。第一个有效(假设我注释掉第二个足够长的时间来测试代码)。第二个没有。它会抛出一个编译器错误,提示“无法将类型 'some View' 的值分配给类型 'Content'。

我在这里做错了什么?我能够使用 Infobox() { Text("Some Text") } 从结构外部成功调用第一个初始化程序,在我看来,这与我尝试从第二个初始化程序调用它时使用的语法完全相同。不管我 google 有多少,我似乎都想不通。

如果您能提供任何帮助,我将不胜感激。

struct Infobox<Content>: View where Content: View {

    let content: Content

    var body: some View {
        content
    }

    init(@ViewBuilder _ content: @escaping () -> Content) {
        self.content = content()
    }

    init(withHeader headerText: String, @ViewBuilder _ content: @escaping () -> Content) {
        self.init() {
            VStack(alignment: .leading) {
                Text(headerText)
                    .font(.headline)
                }
                content()
            }
        }
    }
}

你的意思大概是这样的:

init<T: View>(withHeader headerText: String, @ViewBuilder _ content: @escaping () -> T) 
    where Content == VStack<TupleView<(Text, T)>> {
    self.init {
        VStack(alignment: .leading) {
            Text(headerText)
                .font(.headline)
            content()
        }
    }
}

此初始化程序创建的视图将始终采用以下形式(是的)

InfoBox<VStack<TupleView<(Text, SomeOtherView)>>>

换句话说,这个 init 决定了 Content 应该是什么。所以它只适用于 InfoBoxes with Content == ThatLongTypeName,因此约束。

注意调用者可以指定SomeOtherView的类型,但那不是ContentContentVStack<TupleView<(Text, SomeOtherView)>>。因此,多加了一个泛型参数,闭包return类型发生了变化。


IMO,如果你这样做会简单得多:

struct Infobox<Content>: View where Content: View {

    let content: () -> Content
    let headerText: String

    var body: some View {
        VStack(alignment: .leading) {
            if !headerText.isEmpty {
                Text(headerText)
                    .font(.headline)
            }
            content()
        }
    }

    // note the optional parameter here
    init(withHeader headerText: String = "", @ViewBuilder _ content: @escaping () -> Content) {
        self.content = content
        self.headerText = headerText
    }
}