首页 > 解决方案 > 一个swiftUI问题:应用状态属性的麻烦

问题描述

我正在尝试使用需要计时器的 SwiftUI 构建提醒。

我的问题是,由于缺少 State 变量,时间变量(包括小时、分钟和秒)无法在 GUI 上更新。

而在我的情况下,我不知道如何将绑定变量times(首先通过确保它是两位数字符串的方法)转换为状态变量。body 变量不允许我在里面做,我也不能在外面使用绑定变量和函数。我应该怎么办?

import SwiftUI

struct PresentView: View {
    @Binding var times: DataStorage
    @State private var hourOut = "" // Stuck at here
    @State private var AlertPresent = false
    @State private var timerRun = false
    
    let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect()
    
    func DigitPresent(time: Int) -> String {
        guard time > 9 else {
            return "0\(String(time))"
        }
        return String(time)
    }
    
    var body: some View {
        VStack {
            Text("\(DigitPresent(time: times.hour)) : \(DigitPresent(time: times.minute)) : \(DigitPresent(time: times.second))")
                .font(.largeTitle)
                .fontWeight(.bold)
                .padding(.bottom)
                .onReceive(timer, perform: { _ in
                    if (timerRun == true) {
                        if (times.second > 0) {
                            times.second -= 1
                        } else if (times.minute > 0) {
                            times.minute += 59
                            times.minute -= 1
                        } else if (times.hour > 0) {
                            times.minute += 59
                            times.second += 59
                            times.hour -= 1
                        } else {
                            AlertPresent = true
                            timer.upstream.connect().cancel()
                        }
                    }
                })
                .alert(isPresented: $AlertPresent, content: {
                    Alert(title: Text("Time over"), message: nil, dismissButton: .default(Text("OK"), action: {
                        AlertPresent = false
                    }))
                })
            Button(action: {
                timerRun = true
            }, label: {
                Text("Start/Stop")
            })
        }
    }
}

struct PresentView_Previews: PreviewProvider {
    static var previews: some View {
        PresentView(times: .constant(DataStorage.data[0]))
    }
}

现在我正在尝试将 EnvironmentObject 应用到这个视图中。虽然问题是,还有其他使用绑定属性变量的视图使用 NavigationView 链接到此视图,这会导致错误数据类型的错误:

struct SetView: View {
    @Binding var cards: [DataStorage]
    @State private var sheetPresent = false
    @State private var newReminder = DataStorage.dataOutput()
    
    var body: some View {
        List {
            ForEach (cards) { card in
                NavigationLink(destination: PresentView(times: connect(to: card))) {
                    CardView(info: card)
                }
                .listRowBackground(card.color)
            }
        }
        .navigationTitle("information")
        .navigationBarItems(trailing: Button(action: {
            sheetPresent = true
        }, label: {
            Image(systemName: "plus")
        }))
        .sheet(isPresented: $sheetPresent, content: {
            NavigationView {
                EditView(storedData: $newReminder)
                    .navigationBarItems(leading: Button("Delete", action: {
                        sheetPresent = false
                    }), trailing: Button("Add", action: {
                        let information = DataStorage(title: newReminder.title, hour: newReminder.hour, minute: newReminder.minute, second: newReminder.second, color: newReminder.color)
                        cards.append(information)
                        sheetPresent = false
                }))
            }
        })
    }
    private func connect (to card: DataStorage) -> EnvironmentObject<DataStorage> {
        guard let cardNumber = cards.firstIndex(where: {$0.id == card.id}) else {
                fatalError("Can't find card")
        }
        return $cards[cardNumber] // The error starts here
    }
}

我应该怎么办?修复连接功能或更改“卡片”变量的属性?

标签: swiftswiftui

解决方案


我看不到您的 DataStorage 变量,但我会说使其成为符合@ObservableObject 的类,然后将@Published 应用于小时、分钟、秒。

然后将时间声明为 @ObservedObject 而不是 @Binding 。

我还将您在 onReceive 中的逻辑移动到 DataStorage - 您的视图应该只关心告诉它更新,而不是如何更新。


推荐阅读