Swiftui @状态初始值未在init()上重置变量

Swiftui @状态初始值未在init()上重置变量,swiftui,Swiftui,我有一个分段控件,我正在使用它作为我的应用程序工具栏中链接到selectedTab变量的选项卡。切换选项卡时,帐户列表会更改,但不会重置行列表。我尝试在所选的上使用initialValue以确保它重置为0,但这没有影响它。我尝试在init中打印,以确保在init之后selected的值为0。每次都是这样,但仍然没有刷新每个列表的行 我错过了什么 import SwiftUI import SQLite3 struct ContentView:View { @EnvironmentOb

我有一个分段控件,我正在使用它作为我的应用程序工具栏中链接到selectedTab变量的选项卡。切换选项卡时,帐户列表会更改,但不会重置行列表。我尝试在所选的上使用initialValue以确保它重置为0,但这没有影响它。我尝试在init中打印,以确保在init之后selected的值为0。每次都是这样,但仍然没有刷新每个列表的行

我错过了什么

import SwiftUI
import SQLite3

struct ContentView:View {

    @EnvironmentObject var shared:SharedObject

    var body: some View {
        VStack {
            if shared.selectedTab == 0 {
                LedgerView(ledger: .Accounts)
            } else if shared.selectedTab == 1 {
                LedgerView(ledger: .Budgets)
            } else if shared.selectedTab == 2 {
                ReportsView()
            }
        }.frame(maxWidth: .infinity, maxHeight: .infinity)
    }

}

struct LedgerView:View {

    @EnvironmentObject var shared:SharedObject

    let ledger:LedgerType
    @State var selected:Int = 0

    init(ledger:LedgerType) {
        self.ledger = ledger
        self._selected = State(initialValue: 0)
    }

    var body:some View {
        HStack {
            VStack(alignment: HorizontalAlignment.leading) {
                ForEach(shared.accounts.filter({$0.ledger == ledger})) { account in
                    Text(account.name)
                        .background(account.id == self.selected ? Color.accentColor : Color.clear)
                        .onTapGesture {self.selected = account.id}
                }
            }
            Divider()
            VStack(alignment: HorizontalAlignment.leading) {
                ForEach(shared.journalLines.filter({$0.accountID == selected})) { line in
                    Text("Line#\(line.id)")
                }
            }
        }
    }

}

struct ReportsView:View {
    var body:some View {
        Text("Under Construction ...")
    }
}

class SharedObject:ObservableObject {

    @Published var accounts:[Account] = []
    @Published var journalLines:[JournalLine] = []
    @Published var selectedTab:Int = 0

    init() {
        loadData()    
    }

}

enum LedgerType:Int {
    case Accounts=0,Budgets=1
    var name:String {
        switch(self) {
        case .Accounts: return "Accounts"
        case .Budgets: return "Budgets"
        }
    }
}
struct Account:Identifiable {
    var id:Int
    var name:String
    var ledger:LedgerType
}
struct Payee:Identifiable {
    var id:Int
    var name:String
}
struct Journal:Identifiable {
    var id:Int
    var date:Date
    var payeeID:Int
    var memo:String?
}
struct JournalLine:Identifiable {
    var id:Int
    var journalID:Int
    var accountID:Int
    var amount:Double
}
编辑节略的演示代码,尝试隔离问题

import SwiftUI

struct ContentView: View {

    @EnvironmentObject var shared:SharedObject

    var body: some View {
        VStack {
            Picker(selection: $shared.selectedTab, label: Text("")) {
                Text("Accounts").tag(0)
                Text("Budgets").tag(1)
            }.pickerStyle(SegmentedPickerStyle())
            Divider()
            if shared.selectedTab == 0 || shared.selectedTab == 1 {
                LedgerView()
            }
            Spacer()
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }

}

struct LedgerView:View {

    @State var selected:Int = 0

    init() {
        self._selected = State(initialValue: 0)
        print("LedgerView.init()")
    }

    var body:some View {
        VStack(alignment: HorizontalAlignment.leading) {
            Text("Selected: \(selected)")
            Picker(selection: $selected, label: Text("")) {
                Text("Account#1").tag(1)
                Text("Account#2").tag(2)
                Text("Account#3").tag(3)
            }
        }
    }

}

class SharedObject: ObservableObject {
    @Published var selectedTab:Int = 0
}

根据你最近的评论,你需要的是@Binding而不是@State。解释:struct LedgerView只是一个单独视图中选择器的摘录。调用LedgerView()时,不会实例化新对象。它只是在该位置添加选择器视图。因此,当需要在切换选项卡上重置选择器时,需要使用绑定重置选择器。这是工作代码。希望能有帮助

struct ContentView: View {

    @EnvironmentObject var shared:SharedObject
    @State var selected: Int = 0

    var body: some View {
        VStack {
            Picker(selection: $shared.selectedTab, label: Text("")) {
                Text("Accounts").tag(0)
                Text("Budgets").tag(1)
            }.pickerStyle(SegmentedPickerStyle())
            Divider()
            if shared.selectedTab == 0 || shared.selectedTab == 1 {
                LedgerView(selected: $selected)
            }
            Spacer()
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .onReceive(shared.$selectedTab) { newValue in
            self.selected = 0
        }
    }
}

struct LedgerView:View {

    @Binding var selected: Int

    var body:some View {
        VStack(alignment: HorizontalAlignment.leading) {
            Text("Selected: \(selected)")
            Picker(selection: $selected, label: Text("")) {
                Text("Account#1").tag(1)
                Text("Account#2").tag(2)
                Text("Account#3").tag(3)
            }
        }
    }
}

[先前的答案包含替代解决方案]

我已经修改了你的代码使代码行正常工作。我添加了示例数据以使代码正常工作。我怀疑问题是否出在你的数据上。此外,我还修改了enum LedgerType,使其具有可移植性。这是工作代码

我在代码中修改了以下内容:

  • 删除将ledgerType传递给LedgerView,因为真相的来源是

    @环境对象变量共享:SharedObject

  • 添加了切换选项卡时默认选择第一个帐户的代码。这将在选项卡之间切换时刷新行。请参阅.onReceive中的代码

  • 希望这有帮助。如果你需要什么,请告诉我

    struct ContentView:View {
    
        @EnvironmentObject var shared: SharedObject
    
        var body: some View {
            VStack {
                Picker(selection: $shared.selectedTab, label: Text("")) {
                    ForEach(0 ..< LedgerType.allCases.count) { index in
                        Text(LedgerType.allCases[index].rawValue).tag(index)
                    }
                }
                .pickerStyle(SegmentedPickerStyle())
    
                if shared.selectedTab == 0 || shared.selectedTab == 1 {
                    LedgerView()
                } else if shared.selectedTab == 2 {
                    ReportsView()
                }
                Spacer()
            }.frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    
    }
    
    struct LedgerView:View {
        @EnvironmentObject var shared:SharedObject
        @State var selected: Int = 0
    
        var body:some View {
            HStack {
                VStack(alignment: HorizontalAlignment.leading) {
                    ForEach(shared.accounts.filter({ $0.ledger == LedgerType.allCases[shared.selectedTab] })) { account in
                        Text(account.name)
                            .background(account.id == self.selected ? Color.accentColor : Color.clear)
                            .onTapGesture {self.selected = account.id}
                    }
                }
                Divider()
                VStack(alignment: HorizontalAlignment.leading) {
                    ForEach(shared.journalLines.filter({$0.accountID == selected})) { line in
                        Text("Line#\(line.id)")
                    }
                }
            }
            .onReceive(shared.$selectedTab) { newValue in
                if let id = self.shared.getInitialAccountId(tabIndex: newValue) {
                    self.selected = id
                }
            }
        }
    }
    
    struct ReportsView:View {
        var body:some View {
            Text("Under Construction ...")
        }
    }
    
    class SharedObject:ObservableObject {
    
        @Published var accounts:[Account] = []
        @Published var journalLines:[JournalLine] = []
        @Published var selectedTab:Int = 0
    
        func getInitialAccountId(tabIndex: Int) -> Int? {
            if tabIndex == 0 {
                return accounts.filter({
                    $0.ledger == LedgerType.Accounts
                }).first?.id
            }
            else if tabIndex == 1 {
                return accounts.filter({
                    $0.ledger == LedgerType.Budgets
                }).first?.id
            }
            else {
                return accounts.filter({
                    $0.ledger == LedgerType.Reports
                }).first?.id
            }
        }
    
        init() {
            accounts = [
                Account(id: 1, name: "Sales", ledger: .Accounts),
                Account(id: 2, name: "Purchase", ledger: .Accounts),
                Account(id: 3, name: "Forecast", ledger: .Budgets)
            ]
            journalLines = [
                // Line for sales
                JournalLine(id: 1, journalID: 10, accountID: 1, amount: 200),
                JournalLine(id: 2, journalID: 20, accountID: 1, amount: 400),
                // Line for purchase
                JournalLine(id: 3, journalID: 30, accountID: 2, amount: 600),
                JournalLine(id: 4, journalID: 40, accountID: 2, amount: 800)
            ]
        }
    
    }
    
    enum LedgerType: String, CaseIterable {
        case Accounts = "Accounts"
        case Budgets = "Budgets"
        case Reports = "Reports"
    }
    
    struct Account:Identifiable {
        var id:Int
        var name:String
        var ledger:LedgerType
    }
    
    struct Payee:Identifiable {
        var id:Int
        var name:String
    }
    
    struct Journal:Identifiable {
        var id:Int
        var date:Date
        var payeeID:Int
        var memo:String?
    }
    
    struct JournalLine:Identifiable {
        var id:Int
        var journalID:Int
        var accountID:Int
        var amount:Double
    }
    
    struct ContentView:View{
    @环境对象变量共享:SharedObject
    var body:一些观点{
    VStack{
    选择器(选择:$shared.selectedTab,标签:文本(“”)){
    ForEach(0..Int{
    如果tabIndex==0{
    返回帐户.filter({
    $0.ledger==LedgerType.Accounts
    }).第一个?.身份证
    }
    如果tabIndex==1,则为else{
    返回帐户.filter({
    $0.ledger==LedgerType.Budgets
    }).第一个?.身份证
    }
    否则{
    返回帐户.filter({
    $0.ledger==LedgerType.Reports
    }).第一个?.身份证
    }
    }
    init(){
    账户=[
    账户(id:1,名称:“销售”,分类账:。账户),
    账户(id:2,名称:“采购”,分类账:。账户),
    账户(id:3,名称:“预测”,分类账:。预算)
    ]
    日记行=[
    //销售线
    日记行(id:1,日记id:10,帐户id:1,金额:200),
    日记行(id:2,日记id:20,帐户id:1,金额:400),
    //购买线
    日记行(id:3,日记id:30,帐户id:2,金额:600),
    日记行(id:4,日记id:40,accountID:2,金额:800)
    ]
    }
    }
    枚举分类帐类型:字符串,可大小写{
    case Accounts=“Accounts”
    案例预算=“预算”
    案例报告=“报告”
    }
    结构帐户:可识别{
    变量id:Int
    变量名称:String
    var分类账:分类账类型
    }
    结构收款人:可识别{
    变量id:Int
    变量名称:String
    }
    结构日志:可识别{
    变量id:Int
    var日期:日期
    变量payeid:Int
    var备注:字符串?
    }
    结构日志行:可识别{
    变量id:Int
    var journalID:Int
    var accountID:Int
    风险价值金额:双倍
    }
    
    根据您最近的评论,您需要的是@Binding而不是@State。解释:struct LedgerView只是一个单独视图中选择器的摘录。调用LedgerView()时,不会实例化新对象。它只是在该位置添加选择器视图。因此,当需要在切换选项卡上重置选择器时,需要使用绑定重置选择器。这是工作代码。希望能有帮助

    struct ContentView: View {
    
        @EnvironmentObject var shared:SharedObject
        @State var selected: Int = 0
    
        var body: some View {
            VStack {
                Picker(selection: $shared.selectedTab, label: Text("")) {
                    Text("Accounts").tag(0)
                    Text("Budgets").tag(1)
                }.pickerStyle(SegmentedPickerStyle())
                Divider()
                if shared.selectedTab == 0 || shared.selectedTab == 1 {
                    LedgerView(selected: $selected)
                }
                Spacer()
            }
            .padding()
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .onReceive(shared.$selectedTab) { newValue in
                self.selected = 0
            }
        }
    }
    
    struct LedgerView:View {
    
        @Binding var selected: Int
    
        var body:some View {
            VStack(alignment: HorizontalAlignment.leading) {
                Text("Selected: \(selected)")
                Picker(selection: $selected, label: Text("")) {
                    Text("Account#1").tag(1)
                    Text("Account#2").tag(2)
                    Text("Account#3").tag(3)
                }
            }
        }
    }
    

    [先前的答案包含替代解决方案]

    我已经修改了你的代码使代码行正常工作。我添加了示例数据以使代码正常工作。我怀疑问题是否出在你的数据上。我也