【问题标题】:SwiftUI not updating state variable in ForEach loop function callSwiftUI 不更新 ForEach 循环函数调用中的状态变量
【发布时间】:2020-11-13 19:37:35
【问题描述】:

经过多次搜索,我似乎无法找到解决方案。我正在尝试在函数调用addDay 中更新我的状态变量d。这个函数在 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)
                        
                        
                    }
                    
                }
            }
        }
        
    }
}

【问题讨论】:

    标签: swift foreach swiftui


    【解决方案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 多么方便!

    【讨论】:

      【解决方案2】:

      我不确定您尝试实现什么,但这里有一个演示如何在视图生成期间使用临时变量。

      使用 Xcode 12 / iOS 14 测试(保留原始逻辑)

      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)
                      }
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-26
        • 1970-01-01
        • 1970-01-01
        • 2020-04-11
        • 1970-01-01
        相关资源
        最近更新 更多