【问题标题】:Runtime error: precondition failure: attribute failed to set an initial value运行时错误:前置条件失败:属性未能设置初始值
【发布时间】:2020-02-22 16:46:12
【问题描述】:

我有一个视图 BugSplitView 单独工作正常但会导致

前置条件失败:属性设置初始值失败

在预览或模拟器中导航到时出错。

视图的上部(颜色)和下部(颜色)由水平按钮栏分隔,并使用 GeometeryReader 和split 状态进行布局。当它是 NavigationButton 的目的地时,它不会在预览中正确显示,并在模拟器中运行时报告上面的断言。删除 BugButtonBar 即可。把我难住了!帮助。

import SwiftUI

struct BugSplitView: View {
    @State var split : CGFloat = 0.75
    var buttons : [BugButtonBar.Info]{
        [BugButtonBar.Info(title: "title", imageName: "text.insert"){}]
    }
    var body: some View {
        GeometryReader{ g in
            VStack(spacing: 0){
                Color.gray
                    .frame(width: g.size.width, height: (g.size.height) * self.split)
                VStack{
                    BugButtonBar(infos: self.buttons)
                    Color(white: 0.3)
                }
                    .frame(height: (g.size.height) * (1 - self.split))
            }
        }.edgesIgnoringSafeArea(.all)
    }
}


struct BugButtonBar : View{

    struct Info : Identifiable {
        var id = UUID()
        var title : String
        var imageName : String
        var action: () -> Void
    }

    var infos : [Info]
    func color() -> Color{
        Color.black
    }
    var body: some View {
        HStack(){
            Spacer()
            ForEach(self.infos){ info in
                Button(action: info.action){
                    Text(info.title)
                }
                Spacer()
            }
        }
    }
}


struct ShowBugView : View{
    var body : some View{
        NavigationView {
            NavigationLink(destination: BugSplitView()){
                Text("Show Bug")
            }
        }
    }
}


struct BugSplitView_Previews: PreviewProvider {
    static var previews: some View {
        Group{
            BugSplitView()
            ShowBugView()
        }
    }
}

【问题讨论】:

    标签: swiftui navigationlink


    【解决方案1】:

    问题是您的按钮被声明为计算属性。要解决崩溃,请像这样声明它们:

    var buttons = [BugButtonBar.Info(title: "title", imageName: "text.insert"){}]
    

    【讨论】:

    • 谢谢。我想你的回答补充了我的下面。既然是计算出来的,新的 id 每次都被 swift 弄糊涂了。
    • 这种方法的缺点是动作代码不能引用封闭结构的变量,因为 self 还不可用。
    • @LuLuGaGa 你能解释一下为什么这是一个解决方案吗?
    • 在纯 Swift 中,此更改应该不会影响生成的结构,但是,在 SwiftUI 中处理这些突变的方式可能存在错误。我建议通过 SwiftUI 下的反馈助手 (feedbackassistant.apple.com) 提交错误报告,并使用解决方法,直到我们可以进一步查看。
    • 底线:答案是该问题的合法解决方法,但每次遇到类似情况时提交错误报告。
    【解决方案2】:

    对我来说,它是导航栏标题中的 displayMode 内联。删除它可以解决此问题。

    崩溃

    .navigationBarTitle("Title", displayMode: .inline)
    

    没有崩溃

    .navigationBarTitle("Title")
    

    【讨论】:

    • 谢谢!出于某种原因,我只在启用 VoiceOver 时出现崩溃,它工作正常。删除 displayMode 修复了启用 VoiceOver 时的崩溃问题。我不知道你是怎么想出来的。
    【解决方案3】:

    原来 struct Info 的 id 属性是问题所在。将其更改为计算属性,如下所示:

    var id : String {
       title + imageName
    }
    

    我为什么喜欢/讨厌 SwiftUI 的一个很好的例子。

    【讨论】:

      【解决方案4】:

      由于这个错误(无法直接调试)似乎是由许多不同的问题引起的,所以我想我也要把我的案例放在这里。

      就我而言,我得到的错误是:

      前置条件失败:属性设置初始值失败 - 128

      问题是我试图在 VStack 上显示一个工作表,其中包含一个 NavigationView,如下所示:

      var body: some View {
          VStack(alignment: .center) {
              if /* some condition */ {
                  /* some other content */
              } else {
                  NavigationView {
                      /* view content */
                  }
              }
          }.sheet(isPresented: /* Binding value */) { 
              /* sheet content */
          }
      }
      

      解决方法是确保工作表显示在 NavigationView 上:

      var body: some View {
          NavigationView {
              VStack(alignment: .center) {
                  if /* some condition */ {
                      /* some other content */
                  } else {
                      /* view content */
                  }
              }
          }.sheet(isPresented: /* Binding value */) { 
              /* sheet content */
          }
      }
      

      事后看来似乎很明显,但在崩溃发生时获得更多信息会很好。

      【讨论】:

        【解决方案5】:

        我遇到了这个错误。就我而言,这是由于在 if-else 语句的两个块中都有 NavigationView 引起的。

        // bad
        if someBool {
          NavigationView {
            Text("some content")
          }
        } else {
          NavigationView {
            Text("different content")
          }
        }
        
        // good
        NavigationView {
          if someBool {
            Text("some content")
          } else {
            Text("different content")
          }
        }
        

        【讨论】:

          【解决方案6】:

          在我的例子中,当视图消失时,它为绑定属性设置了一个值,一个像这样改变视图的属性:

            .onDisappear(perform: {
              withAnimation(.easeInOut) {
                  self.action.collageWidthSize = 2.0 /* modifies next view border */
                }
             })
          

          在下一个视图的 onAppear 中设置它修复了它:

             .onAppear {
                  withAnimation(.easeInOut) {
                      self.action.collageWidthSize = 2.0
                  }
              }
          

          【讨论】:

            【解决方案7】:

            好吧,我被这个咬了。 Xcode 11.6。

            我的视图可能有点令人费解,但我正在做的是,如果用户将视图置于“编辑”模式,所有单元格都会更改其呈现方式。当我切换回来时,我似乎随机地收到了这个错误。我通过删除不必要的绑定来修复它(手指仍然交叉)。我将布尔绑定传递给一些子视图,以便他们知道事物处于什么状态以及如何呈现。问题是,他们不需要响应布尔值的变化,因为无论如何都会重绘父级,它可以重新创建子级。他们不需要被通知他们应该改变状态,他们只是被销毁并重新创建。

            【讨论】:

              【解决方案8】:

              我用NavigationView作为TabView的根:

              NavigationView {
                 TabView {
                 }
              }
              

              然后在TabView 中我也使用了NavigationView,所以由于这个错误。解决方案是只使用一个NavigationView

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-12-15
                • 2016-07-17
                • 1970-01-01
                • 1970-01-01
                • 2011-02-13
                • 1970-01-01
                相关资源
                最近更新 更多