Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 如何更改@Published var会影响另一个类似@Published var的绑定_Swift_Swiftui - Fatal编程技术网

Swift 如何更改@Published var会影响另一个类似@Published var的绑定

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)

有没有一种方法可以使@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)"){
        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
            }
        })
    }
}