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

Posted

技术标签:

【中文标题】如何将视图条目计数传输到类方法【英文标题】:How to Transmit a View Entry Count to a Class Method 【发布时间】:2021-01-08 00:37:31 【问题描述】:

我在使用视图中的条目数计数时遇到问题。我特别需要知道视图中什么时候没有条目。我已将调试代码放在下面的视图中,并且视图计数 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]   

这是我想从视图 manCurView 中使用 count 的类和方法

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

【问题讨论】:

【参考方案1】:

如果没有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()
                    
                )
            )
        )
    

【讨论】:

Lorem:我向 manCurView 添加了@StateObject 和 .onChange 逻辑。我收到类型'RateStatus'的错误没有成员'onChange'并且不能在属性初始化程序中使用实例成员'currants';属性初始化程序在 'self' 可用之前运行。 checkForUpdates 在调用 API 之前被调用——我不能从 didSet 调用它。如果 manCurView 计数为 0,我无法调用 API RateStatus 上没有示例代码,所以除了 .onChange 是从 Viewbody 调用的 SwiftUI 方法之外,我无法对此发表评论。就像我之前说的,没有最小的可复制产品;我可以复制和粘贴并查看所有内容;我无法具体帮助你。在单独的项目中创建具有相同功能的示例代码,并且所有代码都应该在同一个文件中。 看看上面的代码,你可以看到一个例子【参考方案2】:

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

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

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

感谢您对此的所有帮助。我不知道 *** 上显示的代码建议。我一定会在未来遵循这些准则。盖伦

导入 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()
        
    

【讨论】:

以上是关于如何将视图条目计数传输到类方法的主要内容,如果未能解决你的问题,请参考以下文章

无法为表视图数据源方法传递计数?

如何将 PropertyDescriptors 添加到类而不是覆盖它们?

idea怎么将库添加到类路径

从活动传递数据到类扩展视图

使用MethodType函数将方法绑定到类或实例上

如何使用装饰器将类的方法添加到类内的列表中