类型“()”不能符合View(除非它肯定是一个View,这次没有恶作剧)

Amy*_*ose 2 view picker swift swiftui

我知道这是一个奇怪的标题,但有很多帖子具有相似的标题和完全不同的问题。大多数人View在他们的视图中编写除代码之外的其他内容,而我没有这样做(据我所知)。

我正在尝试Picker与其他BinaryInteger类型兼容,因为它不适用于除 之外的任何类型Int,并且我在使预览正常工作时遇到了一些麻烦。这是代码:

import SwiftUI

struct CompatibilityPicker<Label, SelectionValue, Content> : View where Label : StringProtocol, SelectionValue : BinaryInteger, Content : View {
    
    var content : () -> Content
    var label : Label
    
    @Binding private var _selection : SelectionValue
    
    private var selection: Binding<Int> { Binding<Int>(
        get: {
            Int(_selection)
        },
        set: {
            self._selection = SelectionValue($0)
        })
    }
    
    init(_ label : Label, selection : SelectionValue, content : @escaping () -> Content) {
        self.label = label
        self._selection = selection
        self.content = content
    }
    
    var body: some View {
        Picker(label, selection: selection, content: content)
    }
}

struct CompatibilityPicker_Previews: PreviewProvider {
    @State static var selection : UInt8 = 4
    
    static var previews: some View {
        CompatibilityPicker("Difficulty", selection: selection) { //error : Type'()' cannot conform to 'View'
            Text("Easy").tag(0)
            Text("Normal").tag(1)
            Text("Hard").tag(2)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

是什么赋予了 ?我有一个正常的Picker,使用完全相同的语法并且有效,我不知道我做错了什么。


感谢 @RobMayoff 的解决方案,我又向前迈进了一步,但是出现了看似荒谬的错误,但无法用 cmd+shift+k 清除:

init(_ label : Label, selection : SelectionValue, @ViewBuilder content : @escaping () -> Content) {
    self.content = content
    self.label = label
    self._selection = selection //variable self._selection used before initialised
    // This stays on this line if I change the order,
} // Return from initializer without initialising all stored properties
// That is not true, as far as I can tell
Run Code Online (Sandbox Code Playgroud)

rob*_*off 6

巧妙的是,您试图ViewBuilder在尾随闭包中使用语法,但您没有装饰content注释@ViewBuilder。所以 Swift 推断尾随闭包返回()(也称为Void)。

\n

更改init声明以提及@ViewBuilder

\n
struct CompatibilityPicker<blah blah blah>: View where blah blah blah {\n\n    init(\n        _ label : Label,\n        selection : SelectionValue,\n        @ViewBuilder content : @escaping () -> Content\n     // ^^^^^^^^^^^^\n    ) {\n        blah blah blah\n
Run Code Online (Sandbox Code Playgroud)\n

更新

\n
    @Binding private var _selection : SelectionValue\n\n    blah blah blah\n\n    init(_ label : Label, selection : SelectionValue, content : @escaping () -> Content) {\n        self.label = label\n        self._selection = selection\n        self.content = content\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

_selection变量由包装器包装Binding,这意味着它实际上是一个计算属性。存储的属性被命名__selection(注意两个下划线)并且类型为Binding<SelectionValue>。因为_selection是计算属性,init所以在所有存储的属性都初始化之前不能提及它。也许你应该改变init以采取Binding<SelectionValue>争论而不是SelectionValue参数:

\n
    init(\n        _ label : Label,\n        selection : Binding<SelectionValue>,\n        @ViewBuilder content : @escaping () -> Content\n     // ^^^^^^^^^^^^\n    ) {\n        self.label = label\n        self.content = content\n        __selection = selection\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

更新2

\n

我查看了您的其他问题和您的代码,我想我知道您的意思 \xe2\x80\x9cit 不适用于除Int\xe2\x80\x9d 之外的任何东西。

\n

问题是,当你说 时Text("Easy").tag(0),Swift 将0其视为Int. 如果您的Picker\SelectionValue是,比如说,Int16那么确实Picker将无法使用0标记,因为类型不匹配。

\n

您可以通过提供正确的类型tag来完成您的工作。例如:。Picker0Text("Easy").tag(0 as Int16)

\n

然而,我的建议是你不要再胡思乱想了CompatibilityPicker这是原始痴迷的症状。惯用的解决方案是使用 anenum作为标签:

\n
enum Difficulty: Hashable {\n    case easy\n    case medium\n    case hard\n}\n\nstruct Demo1: View {\n    @State var difficulty: Difficulty = .easy\n\n    var body: some View {\n        Picker("Difficulty", selection: $difficulty) {\n            Text("Easy").tag(Difficulty.easy)\n            Text("Medium").tag(Difficulty.medium)\n            Text("Hard").tag(Difficulty.hard)\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

你可以更进一步,这样做:

\n
extension Difficulty: CaseIterable { }\n\nextension Difficulty {\n    var stringKey: LocalizedStringKey {\n        switch self {\n        case .easy: return "Easy"\n        case .medium: return "Medium"\n        case .hard: return "Hard"\n        }\n    }\n}\n\nstruct Demo2: View {\n    @State var difficulty: Difficulty = .easy\n\n    var body: some View {\n        Picker("Difficulty", selection: $difficulty) {\n            ForEach(Difficulty.allCases, id: \\.self) {\n                Text($0.stringKey).tag($0)\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n