如何使swiftui结构可变
Posted
技术标签:
【中文标题】如何使swiftui结构可变【英文标题】:How to make swiftui struct mutable 【发布时间】:2021-01-31 09:31:03 【问题描述】:我有以下结构:
struct Communication: Identifiable
let id: String
let message, title: String
let date: Date
var isExpanded: Bool = false
问题是当我尝试更改isExpanded
的值时,我得到了错误:
不能对不可变值使用变异成员:'communication' 是一个'let' 常量
我正在尝试在SwiftUI
中的List()
中使用它
在 Swift 中,这类问题的正确解决方案是什么?
我使用 DatabaseService
类来获取结果:
class DatabaseService : ObservableObject
@Published var communications = [Communication]()
funct getCommunications() -> Void
//...Add items to communications
然后在我看来
struct MainView: View
@ObservedObject var databaseService = DatabaseService()
var body: some View
List(databaseService.communications) communication in
VStack(alignment: .leading)
Text(communication.title)
.bold()
.font(.title3)
Text(communication.message)
.padding(.bottom, 24)
.lineLimit(communication.isExpanded ? nil : 5)
.overlay(
GeometryReader proxy in
Button(action:
communication.isExpanded.toggle()
)
Text(communication.isExpanded ? "Mai puțin" : "Mai mult")
.font(.caption).bold()
.padding(.leading, 8.0)
.padding(.top, 8.0)
.frame(width: proxy.size.width, height: proxy.size.height, alignment: .bottomTrailing)
)
.onAppear(perform:
self.databaseService.getComunicate()
)
【问题讨论】:
我认为这是因为您正在创建一个Communication
变量,即 let
。在您的代码中搜索 let communication
并将其更改为 var communication
。它与结构本身无关
@אוריorihpt 它是 swiftui 中的一个列表,该变量是列表中的迭代。
这取决于您如何在 SwiftUI 视图中定义它。您会显示相关视图吗?
@Asperi 我已经改变了问题。
【参考方案1】:
是的,在ForEach
容器中,您使用的是数据元素的恒定副本,因此无法更改它(即使您愿意,无论如何它都是副本,所以没有意义)。相反,我们必须修改相应的元素 inside 视图模型集合,比如
@ObservedObject var ds = DatabaseService() // << to shorten
var body: some View
List(ds.communications.indices, id: \.self) i in
VStack(alignment: .leading)
Text(ds.communications[i].title)
.bold()
.font(.title3)
Text(ds.communications[i].message)
.padding(.bottom, 24)
.lineLimit(ds.communications[i].isExpanded ? nil : 5)
.overlay(
GeometryReader proxy in
Button(action:
ds.communications[i].isExpanded.toggle() // << now modified in VM !!
)
Text(ds.communications[i].isExpanded ? "Mai puțin" : "Mai mult")
.font(.caption).bold()
.padding(.leading, 8.0)
.padding(.top, 8.0)
.frame(width: proxy.size.width, height: proxy.size.height, alignment: .bottomTrailing)
)
【讨论】:
我们的对象不应该扩展一些东西以便我们可以使用 id: \.self 吗? 我们通过索引而不是对象进行迭代。【参考方案2】:将选择逻辑提取到您的 DatabaseService 是最干净的:
class DatabaseService : ObservableObject
@Published private(set) var communications = [Communication]()
public func didSelect(_ communication: Communication) -> Void
// find the index of the communication tapped by user
guard let selectedIndex = communications.firstIndex(where: $0.id == comunication.id ) else
return
// make a local copy so you can mutate it
var communication = communication
// toggle the selection
comunication.selected.toggle()
// assign the updated value to right index in the array, which will trigger the Publisher
communications[selectedIndex] = comunication
然后在你的视图中你可以这样调用函数:
Button(action: databaseService.didSelect(communication) )
而且您不需要更改任何其他内容。
【讨论】:
以上是关于如何使swiftui结构可变的主要内容,如果未能解决你的问题,请参考以下文章
如何构造值以使所有视图都可以在 Swift/SwiftUI 中访问其值?
Swiftui 无法分配给属性:'self' 是不可变的错误
在 SwiftUI 中将视图添加到层次结构时如何动画过渡