当我研究Kodeco的SwiftUI Apprentice一书时,我发现了下面的代码片段.

struct CountdownView: View {
  let date: Date
  @Binding var timeRemaining: Int
  let size: Double

  var body: some View {
    Text("\(timeRemaining)")  // 5
      .font(.system(size: size, design: .rounded))
      .padding()
      .onChange(of: date) { _ in  // 6
        timeRemaining -= 1
      }
  }
}

struct TimerView: View {
  @State private var timeRemaining: Int = 3  // 1
  @Binding var timerDone: Bool  // 2
  let size: Double

  var body: some View {
    TimelineView(  // 3
      .animation(
        minimumInterval: 1.0,
        paused: timeRemaining <= 0)) { context in
          CountdownView(  // 4
            date: context.date,
            timeRemaining: $timeRemaining,
            size: size)
        }
        .onChange(of: timeRemaining) { _ in
          if timeRemaining < 1 {
            timerDone = true  // 7
          }
        }
  }
}

struct TimerView_Previews: PreviewProvider {
  static var previews: some View {
    TimerView(timerDone: .constant(false), size: 90)
  }
}

当我判断代码片段时,我首先希望重新创建CountdownView.但在这种情况下,date号房产不会发生变化.然后,我在CountdownView的基础上添加了onAppear个修改器来检测视图的重建.因此,它只创建一次.我提出了一个问题来帮助我理解SwiftUI的视图呈现机制,我仍然在研究这个机制,尽管date属性是一个常量,并且不使用@Binding,但如何可能观察到在SwiftUI中声明为常量的数据的变化?

推荐答案

然后,我给CountdownView添加了onAppear个修改器来检测视图的重建.因此,它只创建一次.

onAppear确实可以用来检测正被重新创建的视图.这里的"重新创造"并不意味着"CountdownView.init被召唤".您可以手写自己的CountdownView.init来检测这一点.

actual thing on the screen被移除并重新创建时,onAppear被调用.例如,当视图的身份发生更改时会发生这种情况(在Demystifying SwiftUI中了解有关身份的更多信息).请注意,您在body中所做的只是提供您试图创建的视图的description个,SwiftUI将根据您的描述创建新的视图(这调用onAppear)或更新现有的视图(这不调用onAppear).这与在UIKit中不同,在UIKit中,创建带有初始化器的UILabel直接创建可以在屏幕上显示的内容.

在您的代码中,您在传递给TimelineView的闭包中调用CountdownView.init.SwiftUI在适当的时间运行这个闭包,当它这样做时,它将返回的View(即您想要的视图的description)与上次返回的View进行比较.

SwiftUI看到您在前面的描述和本描述中都使用了onChange(of: date),因此它比较了这两个描述中的date,并发现它们不相等.因此,它调用您传递给onChange的闭包.

当然,它的实际工作原理要复杂得多,但这应该足以理解为什么您可以使用let常量的onChange.SwiftUI正在将以前版本的视图body与新版本的body进行比较.

Ios相关问答推荐

iPhone:iOS 17.4中没有气压数据

在带有可编码的SWIFT5中,可以轻松处理以美元符号开头的JSON密钥,例如$DATE";

在将Cocoapods更新到1.13.0之后,它抛出错误

iOS 16.4,SwiftUI 底部工作表有时会忽略presentationDetents

在 Swift 项目中使用情节提要加载 obj-c 文件

更改订单时如何保存商品的位置?

uikit中如何触发swiftui功能

动画文本位置

Flutter Aging Person 自定义小部件

在 Swift 中 @MainActor 似乎被 withCheckedContinuation 而不是其他异步调用继承是巧合吗?

如何让替换视图淡入旧视图而不是交叉淡入淡出?

如何在Collection 后更改并保留按钮 colored颜色 ,然后在 SwiftUI 中切换回来?

如何在字段包含字典数组的firestore上查询?

使用 CIImage 支持的 UIImage 设置 UIImageView 时发生罕见的崩溃

辅助功能判断器无法在 macOS Monterey 版本 12.3 上的 Xcode 版本 13.3 上运行

在 Swift 中执行 while 循环

如何使用 swift 显示 .svg 图像

如何更新推送通知服务证书

Xcode 故事板:内部错误.请提交错误

在代码生成的 UIView 上绘制 UIBezierPath