gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 15:48:49 26 4
gpt4 key购买 nike

我知道这是一个奇怪的标题,但有很多帖子具有相似的标题和完全不同的问题。大多数人在他们的 View 中编写除了 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)
}
}
}

什么给了?我有一个普通的 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

最佳答案

恶作剧,你正在尝试使用 ViewBuilder尾随闭包中的语法,但你没有修饰 content@ViewBuilder注解。所以 Swift 推断尾随闭包返回 () (也称为 Void )。

更改 init声明提@ViewBuilder :

struct CompatibilityPicker<blah blah blah>: View where blah blah blah {

init(
_ label : Label,
selection : SelectionValue,
@ViewBuilder content : @escaping () -> Content
// ^^^^^^^^^^^^
) {
blah blah blah

更新

    @Binding private var _selection : SelectionValue

blah blah blah

init(_ label : Label, selection : SelectionValue, content : @escaping () -> Content) {
self.label = label
self._selection = selection
self.content = content
}

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

    init(
_ label : Label,
selection : Binding<SelectionValue>,
@ViewBuilder content : @escaping () -> Content
// ^^^^^^^^^^^^
) {
self.label = label
self.content = content
__selection = selection
}

更新 2

我看了your other question和你的代码在这里,我想我知道你的意思是“它只适用于 Int ”。

问题就是这样,当你说 Text("Easy").tag(0) , Swift对待0作为Int .如果你的PickerSelectionValue比如说,Int16 , 那么确实是 Picker将无法使用 0标记,因为类型不匹配。

你可以让你的tagPicker 一起工作通过给予 0正确的类型。例如:Text("Easy").tag(0 as Int16) .

但是,我的建议是您不要再胡闹 CompatibilityPicker .这是 primitive obsession 的症状.惯用的解决方案是使用 enum对于您的标签:

enum Difficulty: Hashable {
case easy
case medium
case hard
}

struct Demo1: View {
@State var difficulty: Difficulty = .easy

var body: some View {
Picker("Difficulty", selection: $difficulty) {
Text("Easy").tag(Difficulty.easy)
Text("Medium").tag(Difficulty.medium)
Text("Hard").tag(Difficulty.hard)
}
}
}

你可以走得更远,这样做:

extension Difficulty: CaseIterable { }

extension Difficulty {
var stringKey: LocalizedStringKey {
switch self {
case .easy: return "Easy"
case .medium: return "Medium"
case .hard: return "Hard"
}
}
}

struct Demo2: View {
@State var difficulty: Difficulty = .easy

var body: some View {
Picker("Difficulty", selection: $difficulty) {
ForEach(Difficulty.allCases, id: \.self) {
Text($0.stringKey).tag($0)
}
}
}
}

关于swift - 类型 '()'不能符合View(除非它肯定是一个View,这次没有恶作剧),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73254249/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com