【问题标题】:Why is `.onAppear` called twice when view is inside TabView当视图在 TabView 内时,为什么会调用两次`.onAppear`
【发布时间】:2021-03-28 19:50:41
【问题描述】:

我正在尝试加载远程资源,因此我使用.onAppear 来执行此操作。但是,当我在视图中使用 if/else 时,它会导致它触发两次。

class FooVM: ObservableObject {
   @Published var remoteText: String? = nil

   func load() {
      DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
         self.remoteText = "\(Date())"
      }
   }
}

struct Foo: View {

   @StateObject private var vm = FooVM()

   var body: some View {
      content
         .onAppear(perform: vm.load)
   }

   @ViewBuilder
   private var content: some View {
      if let text = vm.remoteText {
         Text(text)
      } else {
         Circle()
      }
   }
}

struct ContentView: View {
    var body: some View {
        TabView {
            Foo()
                .tabItem {
                    Image(systemName: "circle.fill")
                    Text("Home")
                } 
        }
    }
}

编辑:当内容在TabView 中时,它只是复制品。我更新了上面的代码

为什么onAppear(以及load)会触发两次? 实际上,在 Playground 中,它每 2 秒重复触发一次,但在模拟器中只触发两次。

我该如何避免呢?请记住,这是一个简化的示例。


有趣的是,如果不是TextCircle 之间的选择,而只是Text 中的不同文本,那么它只会触发一次:

Text(vm.remoteText ?? "loading...")

【问题讨论】:

  • 对于 Xcode 12.1 / iOS 14.1 load 仅使用提供的代码调用一次。你用的是哪个环境?
  • Xcode 12.2 / iOS 14.2
  • 我在 12.2 / iOS 14.2 上,也只看到 load 调用过一次。您是否在 Playground 之外的模拟器上尝试过?
  • @nicksarno,是的 - 实际上是在模拟器上尝试
  • 好吧,我无法用当前代码重现它。唯一想到的是当内容切换时视图可能会“重新出现”。尝试在 ZStack 中嵌入“内容”并在 ZStack 上调用 .onAppear 。这样在内容重新出现时 ZStack 仍然存在?只是在这里猜测哈哈

标签: swift swiftui


【解决方案1】:

当您的内容在 if 语句中切换时,Foo() 必须完全重新出现。解决方案是将 Foo() 的内容嵌入到 ZStack (或类似的)中,这样它就不需要重新出现整个视图并再次调用 .onAppear 。在这里,当内容切换时,ZStack 仍然出现。

var body: some View {
        ZStack {
            content
        }
        .onAppear(perform: vm.load)
   }

【讨论】:

  • 确实使用VStackZStack(但不是Group)解决了这个问题。谢谢!不过,我不认为您提供的原因(即Foo 需要重新渲染)是正确的,因为Foo 不在TabView 内时不需要重新渲染。另外,为什么VStack/ZStack 不需要重新渲染,而不是_ConditionalContent<Text, Circle>(这就是content)。如果您可以修改解释,我会接受这个作为答案。谢谢
  • 我猜重新渲染是错误的词。它似乎与 .onAppear 位置有关,而不是 TabView。如果您对此有完整的解释,请随时在我的上方添加您自己的答案。
猜你喜欢
  • 2021-08-01
  • 2020-11-24
  • 1970-01-01
  • 2020-11-14
  • 2020-10-28
  • 1970-01-01
  • 1970-01-01
  • 2021-08-06
  • 1970-01-01
相关资源
最近更新 更多