SwiftUI不会在ForEach循环函数调用中更新状态变量

时间:2020-07-24 00:30:09

标签: swift foreach swiftui

经过大量搜索,我似乎找不到解决方案。我正在尝试在函数调用d中更新状态变量addDay。在ForEach循环中调用此函数。问题是,d一次被更新为2.0,然后永远保持2.0。我不确定出什么问题了,有见识吗?

let weekdays: [String] = ["Mon", "Tues", "Wed", "Thurs", "Fri"]
    @State var startDate: Date = Date().next(.monday, direction: .backward)
    @State var d:Double  = 1.0
    
    /**
     - parameter startDate: the beginning date that will be modified
     - Returns: A new Text that has a date attached
     */
    func addDay(startDate: Date) -> Text {
        self.startDate = startDate.addingTimeInterval(86400 * self.d)
        self.d += 1.0
        return Text("\(startDate, formatter: Self.weekFormat)")
    }
    
    static let weekFormat: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "MMMM dd"
        return formatter
    }()
    
    var body: some View {
        ScrollView(.horizontal) {
            HStack{
                ForEach(weekdays, id: \.self) { weekday in
                    VStack{
                        RoundedRectangle(cornerRadius: 9, style: .continuous)
                            .stroke(Color.blue)
                            .frame(width: 68.5, height: 68.5)
                        
                        self.addDay(startDate: self.startDate)
                        Text(String(self.d))
                        Text(weekday)
                        
                        
                    }
                    
                }
            }
        }
        
    }
}

2 个答案:

答案 0 :(得分:1)

看来您可能正在在更新过程中修改视图状态 ...

这是一个可能永无止境的循环的幻想术语:

  1. SwiftUI评估视图,这将导致调用addDay。
  2. addDay导致startDated发生变化,它们都是@State变量。
  3. SwiftUI认为视图状态会发生变化,因此它会重新评估视图。
  4. (返回顶部:P)

您的情况有所不同,因为SwiftUI似乎实际上是在停止状态更改,这在您的情况下可能很好,因为如果不停止状态更改,则CPU使用率会飙升至100%。


但是...我该如何解决?

对于您的特殊情况,我建议按以下方式处理:

func addDay(_ index: Double) -> Text {
    let someDate = startDate.addingTimeInterval(86400 * index)
    return Text("\(someDate, formatter: Self.weekFormat)")
}

...

ForEach(0..<weekdays.count) { weekday in
    VStack{
        RoundedRectangle(cornerRadius: 9, style: .continuous)
            .stroke(Color.blue)
            .frame(width: 68.5, height: 68.5)
        
        self.addDay(Double(weekday))
        Text(String(Double(weekday)))
        Text(self.weekdays[weekday])
        
        
    }
}

这又可以归结为SwiftUI的工作方式,您可以将SwiftUI视为其状态的“功能”。在我的示例中,您可以在工作日中传递 any ,并将其放置在数组中,并且可以生成UI。


-旁注-

不知道您可以使用self(大写S)访问Self的静态版本。 Swift多么方便!

答案 1 :(得分:0)

我不确定您要达到什么目的,但这是一个演示如何在视图生成期间使用临时变量的方法的演示。

在Xcode 12 / iOS 14上进行了测试(保留了原始逻辑)

demo

struct ContentView: View {
    let weekdays: [String] = ["Mon", "Tues", "Wed", "Thurs", "Fri"]
    @State var startDate: Date = Date()//.next(.monday, direction: .backward)

    /**
     - parameter startDate: the beginning date that will be modified
     - Returns: A new Text that has a date attached
     */
    func addDay(startDate: inout Date, d: inout Double) -> Text {
        startDate = startDate.addingTimeInterval(86400 * d)
        d += 1.0
        return Text("\(startDate, formatter: Self.weekFormat)")
    }

    static let weekFormat: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "MMMM dd"
        return formatter
    }()

    var body: some View {
        ScrollView(.horizontal) {
            genererateContent()
        }
    }

    private func genererateContent() -> some View {
        var d: Double = 1.0
        var startDate = self.startDate.addingTimeInterval(86400 * d)

        return HStack{
            ForEach(weekdays, id: \.self) { weekday in
                VStack{
                    RoundedRectangle(cornerRadius: 9, style: .continuous)
                        .stroke(Color.blue)
                        .frame(width: 68.5, height: 68.5)

                    self.addDay(startDate: &startDate, d: &d)
                    Text(String(d))
                    Text(weekday)
                }
            }
        }
    }
}