繁体   English   中英

当 ObservedObject 更改时,不会在 SwiftUI 视图中调用 onReceive

[英]onReceive not getting called in SwiftUI View when ObservedObject changes

每当 ObservedObject 中的变量发生更改时,我都无法在 SwiftUI 视图中触发 onReceive 方法。

我尝试了两种方法:使用@Publish和使用PassthroughSubject<>

这是视图模型

class MenuViewModel: ObservableObject {

@Published var selectedItems = Set<UUID>()
@Published var currentFocusItem: UUID?

// Output
let newItemOnFocus = PassthroughSubject<(UUID?), Never>()

// This function gets called good :)
func tapOnMenuItem(_ item: MenuItem) {
    if selectedItems.contains(item.id) {
        //These changes should trigger the onReceive?
        currentFocusItem = item.id  
        newItemOnFocus.send(item.id)
    } else {
        selectedItems.insert(item.id)
        currentFocusItem = nil
        newItemOnFocus.send(nil)
    }
}
}

这是尝试捕获@Published var currentFocusItem 中的更改时的视图

struct MenuView: View {

    @ObservedObject private var viewModel: MenuViewModel
    @State var showPicker = false
    @State private var menu: Menu = Menu.mockMenu()


    init(viewModel: MenuViewModel = MenuViewModel()) {
        self.viewModel = viewModel
    }

    var body: some View {
        VStack {
            List(menu.items, selection: $viewModel.selectedItems) { item in
                MenuItemView(item: item)
            }

            Divider()
            getBottomView(showPicker: showPicker)
        }

        .navigationBarTitle("Title")
        .navigationBarItems(trailing: Button(action: closeModal) {
            Image(systemName: "xmark")
        })
        .onReceive(viewModel.$currentFocusItem, perform: { itemUUID in
            self.showPicker = itemUUID != nil // <-- This only gets called at launch time
        })           
    }
}

视图以相同的方式但试图捕捉PassthroughSubject<>

.onReceive(viewModel.newItemOnFocus, perform: { itemUUID in
            self.showPicker = itemUUID != nil // <-- This never gets called
        })

- - - - - 编辑 - - - - -

添加 MenuItemView,虽然 viewModel.tapOnMenuItem 总是被调用,所以我不确定它是否非常相关

MenuItemView在这里:

struct MenuItemView: View {

    var item: MenuItem
    @ObservedObject private var viewModel: MenuViewModel = MenuViewModel()
    @State private var isSelected = false

    var body: some View {
        HStack(spacing: 24) {
            Text(isSelected ? " 1 " : item.icon)
                .font(.largeTitle)
                .foregroundColor(.blue)
                .bold()
            VStack(alignment: .leading, spacing: 12) {
                Text(item.name)
                    .bold()
                Text(item.description)
                    .font(.callout)
            }
            Spacer()
            Text("\(item.points)\npoints")
                .multilineTextAlignment(.center)
        }
        .padding()
        .onTapGesture {
            self.isSelected = true
            self.viewModel.tapOnMenuItem(self.item). // <-- Here tapOnMenuItem gets called
        }
    }

    func quantityText(isItemSelected: Bool) -> String {
        return isItemSelected ? "1" : item.icon
    }
}

我究竟做错了什么?

好吧,这里是 - 您的MenuViewMenuItemView使用不同的视图模型实例

1)

struct MenuView: View {

    @ObservedObject private var viewModel: MenuViewModel
    @State var showPicker = false
    @State private var menu: Menu = Menu.mockMenu()


    init(viewModel: MenuViewModel = MenuViewModel()) { // 1st one created

2)

struct MenuItemView: View {

    var item: MenuItem
    @ObservedObject private var viewModel: MenuViewModel = MenuViewModel() // 2nd one

因此,您修改了一个实例,但订阅了另一个实例中的更改。 就是这样。

解决方案:通过.environmentObject或通过参数从MenuView传递视图模型到MenuItemView

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM