Swift 如何更改@Published var会影响另一个类似@Published var的绑定
有没有一种方法可以使@Published变量发生变化,从而影响另一个@Published变量(如绑定变量)Swift 如何更改@Published var会影响另一个类似@Published var的绑定,swift,swiftui,Swift,Swiftui,有没有一种方法可以使@Published变量发生变化,从而影响另一个@Published变量(如绑定变量) import SwiftUI struct ContentView: View { @StateObject var viewModel = ViewModel() var body: some View { ForEach(viewModel.items, id: \.self){ item in Button("Select \(item.title)
import SwiftUI
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
ForEach(viewModel.items, id: \.self){ item in
Button("Select \(item.title)"){
viewModel.selectedItem = item
viewModel.selectedItem.title = "grape"
print(viewModel.items) // <-- This will print [Test.Item(title: "Apple"), Test.Item(title: "Banana"), Test.Item(title: "Orange")]
}
}
}
}
struct Item: Hashable {
var title: String
}
class ViewModel: ObservableObject {
@Published var items: [Item] = [Item(title: "Apple"), Item(title: "Banana"), Item(title: "Orange")]
@Published var selectedItem: Item = Item(title: "default") //<-- I want this to be a binding of an item in the bucket above, so what I modify to selectedItem will affect item in the bucket.
}
导入快捷界面
结构ContentView:View{
@StateObject变量viewModel=viewModel()
var body:一些观点{
ForEach(viewModel.items,id:\.self){item in
按钮(“选择\(项目标题)”){
viewModel.selectedItem=项目
viewModel.selectedItem.title=“葡萄”
print(viewModel.items)//三种可能的解决方案——最后一种可能与您所要求的最接近,即一种@Published对另一种@Published的反应
下面是一个使用didSet的版本:
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
ForEach(viewModel.items, id: \.self){ item in
Button("Select \(item.title)"){
viewModel.selectedItem = item
viewModel.selectedItem?.title = "grape"
print(viewModel.items)
}
}
}
}
struct Item: Hashable {
var id = UUID()
var title: String
}
class ViewModel: ObservableObject {
@Published var selectedItem : Item? {
didSet { //when there's a new value, see if it should be mapped into the original item set
self.items = self.items.map {
if let selectedItem = selectedItem, selectedItem.id == $0.id {
return selectedItem
}
return $0
}
}
}
@Published var items: [Item] = [Item(title: "Apple"), Item(title: "Banana"), Item(title: "Orange")]
}
这里有一种可能性,使用自定义的绑定
:
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
ForEach(viewModel.items, id: \.self){ item in
Button("Select \(item.title)"){
viewModel.selectedItemID = item.id
viewModel.selectedItem?.wrappedValue.title = "grape"
print(viewModel.items)
}
}
}
}
struct Item: Hashable {
var id = UUID()
var title: String
}
class ViewModel: ObservableObject {
@Published var selectedItemID : UUID?
@Published var items: [Item] = [Item(title: "Apple"), Item(title: "Banana"), Item(title: "Orange")]
var selectedItem : Binding<Item>? {
guard let selectedItemID = selectedItemID else {
return nil
}
return .init { () -> Item in
self.items.first(where: {$0.id == selectedItemID}) ?? Item(title: "")
} set: { (item) in
self.items = self.items.map {
if $0.id == selectedItemID { return item }
return $0
}
}
}
}
这三个都有相同的功能——这实际上取决于您喜欢的编码风格。我个人可能会选择最后一个选项,因为Combine和SwiftUI往往能很好地协同工作。它也很容易通过过滤等方式进行扩展。您正在将按钮操作的新值设置为viewModel。选择EdItem
您想做什么更多吗?
import SwiftUI
import Combine
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
ForEach(viewModel.items, id: \.self){ item in
Button("Select \(item.title)"){
viewModel.selectedItem = item
viewModel.selectedItem?.title = "grape"
print(viewModel.items)
}
}
}
}
struct Item: Hashable {
var id = UUID()
var title: String
}
class ViewModel: ObservableObject {
@Published var selectedItem : Item?
@Published var items: [Item] = [Item(title: "Apple"), Item(title: "Banana"), Item(title: "Orange")]
private var cancellable : AnyCancellable?
init() {
cancellable = $selectedItem
.compactMap { $0 } //remove nil values
.sink(receiveValue: { (newValue) in
self.items = self.items.map {
newValue.id == $0.id ? newValue : $0 //if the ids match, return the new value -- if not, return the old one
}
})
}
}