如何将视图条目计数传输到 Class 方法

How to Transmit a View Entry Count to a Class Method

我在使用视图中的条目数计数时遇到问题。我特别需要知道什么时候视图中没有条目。我在下面的视图中放置了调试代码,并且视图计数 currants.curItem.count 正在按预期更新。 checkForUpdates() 中的计数状态不符合上述视图。

如果我没记错的话,我应该只在视图中使用@EnvironmentObject 或@ObservedObject。我真的需要某种可以传递给方法 checkForUpdates 的全局变量。当 checkForUpdates() 中的计数为非零时,它会崩溃,而在视图中它实际上为零。它还在 checkForUpdates() 中崩溃,并出现错误 Fatal error: No ObservableObject of type Currencies found。作为此视图的祖先,货币的 View.environmentObject(_:) 可能缺失。

struct manCurView: View {
    
    @EnvironmentObject var currants: Currants
    
    var body: some View {
        List {       
            ForEach(currants.curItem, id: \.id) { item in
                HStack {
                    Text(item.curCode)
                        .frame(width: 100, alignment: .center)
                    
                    Text(item.cunName)
                }
                .font(.subheadline)
            }
            .onDelete(perform: removeItems)
        }
        .navigationBarTitle(Text("Manage Working Blocks"), displayMode: .inline)
        HStack {
            NavigationLink(destination: addCurView()) {Text("Add Working Blocks").fontWeight(.bold)}
                .font(.title2)
                .disabled(currants.curItem.count > 7)

以上视图的数据存储方式如下

struct CurItem: Codable, Identifiable {
    var id = UUID()
    var cunName: String 
    var curName: String
    var curCode: String
    var curSymbol: String 
    var curRate: Double
}

class Currants: ObservableObject {
    
    @Published var curItem: [CurItem]   
}

这是 class 和方法,我想在其中使用来自视图 manCurView

的计数
class BlockStatus:  ObservableObject {
    
    @EnvironmentObject var globalCur : Currants
    @ObservedObject var netStatus : TestNetStatus = TestNetStatus()
    
    func checkForUpdates() -> (Bool) {
        
        if netStatus.connected == true {
            if globalCur.curItem.count > 0 { 

没有 minimal reproducible example 很难给你准确的代码,但你可以在你的 manCurView

中尝试类似下面的代码
@StateObject var blockStatus: BlockStatus = BlockStatus()

.onChange(of: currants.curItem.count, perform: { value in
            print("send value from here")
            blockStatus.arrayCount = value
        })

并将下面的代码添加到 BlockStatus

@Published var arrayCount: Int = 0{
    didSet{
        //Call your method here
    }
}

看下面的代码。

import SwiftUI
import Combine
struct CurItem: Codable, Identifiable {
    var id = UUID()
    
}
class Currants: ObservableObject {
    
    @Published var curItem: [CurItem] = [CurItem(), CurItem(), CurItem(), CurItem()]
}
class TestNetStatus: ObservableObject {
    static let sharedInstance = TestNetStatus()
    @Published var connected: Bool = false
    
    init() {
        //Simulate changes in connection
        Timer.scheduledTimer(withTimeInterval: 10, repeats: true){ timer in
            self.connected.toggle()
        }
    }
}
class BlockStatus:  ObservableObject {
    @Published var arrayCount: Int = 0{
        didSet{
            checkForUpdates()
        }
    }
    @Published var checkedForUpdates: Bool = false
    var netStatus : TestNetStatus = TestNetStatus.sharedInstance
    //private var cancellable: AnyCancellable?
    init() {
        //Maybe? if you want to check upon init.
        //checkForUpdates()
        
        //Something like the code below is also possible but with 2 observed objects the other variable could be outdated
        
        //        cancellable = netStatus.objectWillChange.sink { [weak self] in
        //            self?.checkForUpdates()
        //        }
    }
    
    func checkForUpdates() {
        if netStatus.connected == true {
            if arrayCount > 0 {
                checkedForUpdates = true
            }else{
                checkedForUpdates = false
            }
        }else{
            checkedForUpdates = false
        }
    }
}
struct ManCurView: View {
    @StateObject var currants: Currants = Currants()
    @StateObject var blockStatus: BlockStatus = BlockStatus()
    @StateObject var testNetStatus: TestNetStatus = TestNetStatus.sharedInstance
    var body: some View {
        List {
            Text("checkedForUpdates = " + blockStatus.checkedForUpdates.description).foregroundColor(blockStatus.checkedForUpdates ? Color.green : Color.red)
            Text("connected = " + blockStatus.netStatus.connected.description).foregroundColor(blockStatus.netStatus.connected ? Color.green : Color.red)
            
            ForEach(currants.curItem, id: \.id) { item in
                HStack {
                    Text(item.id.uuidString)
                        .frame(width: 100, alignment: .center)
                    
                    Text(item.id.uuidString)
                }
                .font(.subheadline)
            }
            //Replaced with toolbar button for sample
            //.onDelete(perform: removeItems)
            //When the array count changes
            .onChange(of: currants.curItem.count, perform: { value in
                blockStatus.arrayCount = value
            })
            //Check when the networkStatus changes
            .onChange(of: testNetStatus.connected, perform: { value in
                //Check arrayCount
                if blockStatus.arrayCount != currants.curItem.count{
                    blockStatus.arrayCount = currants.curItem.count
                }else{
                    blockStatus.checkForUpdates()
                }
            })
            
        }
        .navigationBarTitle(Text("Manage Working Blocks"), displayMode: .inline)
        //Replaced addCurView call with toolbar button for sample
        .toolbar(content: {
            ToolbarItem(placement: .navigationBarTrailing, content: {
                Button("add-currant", action: {
                    currants.curItem.append(CurItem())
                })
            })
            ToolbarItem(placement: .navigationBarLeading, content: {
                Button("delete-currant", action: {
                    if currants.curItem.count > 0{
                        currants.curItem.removeFirst()
                    }
                })
            })
        })
    }
}

这是ContentView:注意在菜单中,因为这是一个视图,所以我可以直接使用计数来禁用条目输入。在 getData() 中,请注意我正在调用 blockStatus.checkForUpdates() 以确定是否可以调用 API。如果 currants.curItem.count = 0

将发生错误

我刚刚意识到从技术上讲 getData() 是 ContentView 的一部分,所以我可以将下面的调用更改为 if blockStatus.checkForUpdates() == true && currants.curItem.count != 0 {

我将花一些时间研究您上面的建议,看看我将来是否可以使用它。

非常感谢您对此的所有帮助。我不知道 Whosebug 上显示的代码建议。我一定会在未来遵循这些指导方针。盖伦

导入 SwiftUI 导入核心数据 导入组合

struct ContentView: View {
    
    @EnvironmentObject var userData: UserData
    @EnvironmentObject var currants: Currants
    @EnvironmentObject var blockStatus: BlockStatus
    
    
    var body: some View {
        NavigationView {
            VStack (alignment: .center) {
                
                Text("Title")
                .font(.title)
                .fontWeight(.bold)
                
                Spacer()
                
                Group {
                    NavigationLink(destination: entryView()) {Text("Entry")}
                    .disabled(currants.curItem.count == 0)
                    
                    Spacer()
                    NavigationLink(destination: totalView()) {Text("View Totals")}
                    
                    Spacer()
                    NavigationLink(destination: listView()) {Text("View Entries")}
                    
                    Spacer()
                    NavigationLink(destination: xchView()) {Text("View Dates")}
                }
                
                Rectangle()
                .frame(height: 130)
                .foregroundColor(Color.white)
            }
            .font(.title2)
            .navigationBarItems(leading: NavigationLink (destination: settingsView()) {
                Image(systemName: "gear")
                .foregroundColor(.gray)
                .font(.system(.title3))
                
                
            }, trailing: NavigationLink( destination: aboutView()) {
                Text("About")
            })
            .onAppear(perform: getData)
        }
    }
    
    
    func getData() {
        
        // check criteria for updating data once daily
        if blockStatus.checkForUpdates() == true {
            
            print("  doing update")
            
            ---- API HERE -----



            }.resume()
        }
    }
}