错误:初始化程序 'init(_:)' 要求 'Binding<String>' 符合 'StringProtocol'
Posted
技术标签:
【中文标题】错误:初始化程序 \'init(_:)\' 要求 \'Binding<String>\' 符合 \'StringProtocol\'【英文标题】:Error: Initializer 'init(_:)' requires that 'Binding<String>' conform to 'StringProtocol'错误:初始化程序 'init(_:)' 要求 'Binding<String>' 符合 'StringProtocol' 【发布时间】:2020-01-23 19:08:10 【问题描述】:我收到上述错误,不知道如何解决。我有一个包含布尔值的对象数组,并且需要为每个布尔值显示一个切换。
下面是代码。
class Item: Identifiable
var id: String
var label: String
var isOn: Bool
class Service: ObservableObject
var didChange = PassthroughSubject<Void, Never>()
var items: [Item]
didSet
didChange.send(())
struct MyView: View
@ObservedObject var service: Service
var body: some View
List
ForEach(service.items, id: \.self) (item: Binding<Item>) in
Section(header: Text(item.label)) // Error: Initializer 'init(_:)' requires that 'Binding<String>' conform to 'StringProtocol'
Toggle(isOn: item.isOn)
Text("isOn")
.listStyle(GroupedListStyle())
【问题讨论】:
【参考方案1】:在Service
类中使用@Published
属性包装器,而不是didChange
,并像这样遍历service.items
的索引:
struct Item: Identifiable
var id: String
var label: String
var isOn: Bool
didSet
// Added to show that state is being modified
print("\(label) just toggled")
class Service: ObservableObject
@Published var items: [Item]
init()
self.items = [
Item(id: "0", label: "Zero", isOn: false),
Item(id: "1", label: "One", isOn: true),
Item(id: "2", label: "Two", isOn: false)
]
struct MyView: View
@ObservedObject var service: Service
var body: some View
List
ForEach(service.items.indices, id: \.self) index in
Section(header: Text(self.service.items[index].label))
Toggle(isOn: self.$service.items[index].isOn)
Text("isOn")
.listStyle(GroupedListStyle())
更新:为什么要使用索引?
在这个例子中,我们需要从模型中的每个 Item 中获取两个东西:
label
属性的String
值,用于文本视图。
Binding<Bool>
来自 isOn
属性,用于切换视图。
(请参阅 this answer 我解释绑定的地方。)
我们可以通过直接遍历项目来获取标签值:
ForEach(service.items) (item: Item) in
Section(header: Text(item.label))
...
但 Item 结构不包含绑定。如果您尝试引用 Toggle(isOn: item.$isOn)
,则会收到错误消息:“'Item' 类型的值没有成员 '$isOn'。”
相反,绑定由@ObservedObject 属性包装器在顶层提供,这意味着$
必须位于service
之前。但是如果我们从service
开始,我们需要一个索引(我们不能在 ForEach 结构中声明中间变量,所以我们必须内联计算它):
ForEach(service.items) (item: Item) in
Section(header: Text(item.label))
Toggle(isOn: self.$service.items[self.service.items.firstIndex(of: item)!].isOn)
// This computes the index ^--------------------------------------^
Text("isOn")
哦,找到索引的比较意味着 Item 必须符合 Equatable。而且,最重要的是,因为我们循环遍历 ForEach 中的所有项目,然后再循环 .firstIndex(of:),我们将代码从 O(n) 复杂度转换为 O(n^2),这意味着它将当数组中有大量 Item 时,运行速度会慢得多。
所以我们只使用索引。只是为了衡量,
ForEach(service.items.indices, id: \.self) index in
等价于
ForEach(0..<service.items.count, id: \.self) index in
【讨论】:
这很有趣!为什么它适用于索引而不适用于实际对象? @user1366265 我添加到我的答案中,解释了为什么最容易迭代索引。您可以迭代项目,这并不好玩。 ?以上是关于错误:初始化程序 'init(_:)' 要求 'Binding<String>' 符合 'StringProtocol'的主要内容,如果未能解决你的问题,请参考以下文章
@@ EnvironmentObject初始化程序'init(_ :)'要求'Binding'符合'StringProtocol'
Python 2019/7/24 面向对象概念 类和对象 对象初始化__init__ 绑定与非绑定