iOS17中App后台/多任务返回输入值重置问题咨询
问题解答
1. 后台/多任务返回时是否会触发onAppear导致重置?
是的,iOS17调整了SwiftUI的视图生命周期逻辑,当App从后台回到前台、或进入多任务切换后返回时,视图的onAppear会被重新触发。你的代码中在onAppear里调用了initValue(),这个方法会把edited*系列变量重新赋值为original*的初始值,这就是输入内容被重置的原因。而iOS16中onAppear不会在这类场景下重复触发,所以之前运行正常。
2. iOS17中保留输入值的解决方法
核心思路是让编辑值的初始化只执行一次,避免在onAppear这种会重复触发的回调里重置数据,具体有两种可行方案:
方案一:通过视图初始化器初始化编辑值
把initValue()的逻辑移到视图的自定义初始化器中,这样初始化只会在视图创建时执行一次,不会在后台返回时重复执行:
struct RealSizeView: View { private enum Field: Hashable { case shoulder, chest, sleeve, length, waist, thigh, rise, hem, inseam } let realSizeType: RealSizeType @Binding var originalShoulder: Double @Binding var originalChest: Double @Binding var originalSleeve: Double @Binding var originalLength: Double @Binding var originalWaist: Double @Binding var originalThigh: Double @Binding var originalRise: Double @Binding var originalHem: Double @Binding var originalInseam: Double @State private var editedShoulder: Double = 0 @State private var editedChest: Double = 0 @State private var editedSleeve: Double = 0 @State private var editedLength: Double = 0 @State private var editedWaist: Double = 0 @State private var editedThigh: Double = 0 @State private var editedRise: Double = 0 @State private var editedHem: Double = 0 @State private var editedInseam: Double = 0 @Environment(\.dismiss) private var dismiss // 添加自定义初始化器 init(realSizeType: RealSizeType, originalShoulder: Binding<Double>, originalChest: Binding<Double>, originalSleeve: Binding<Double>, originalLength: Binding<Double>, originalWaist: Binding<Double>, originalThigh: Binding<Double>, originalRise: Binding<Double>, originalHem: Binding<Double>, originalInseam: Binding<Double>) { self.realSizeType = realSizeType self._originalShoulder = originalShoulder self._originalChest = originalChest self._originalSleeve = originalSleeve self._originalLength = originalLength self._originalWaist = originalWaist self._originalThigh = originalThigh self._originalRise = originalRise self._originalHem = originalHem self._originalInseam = originalInseam // 初始化编辑值,仅执行一次 switch realSizeType { case .top: self._editedShoulder = State(initialValue: originalShoulder.wrappedValue) self._editedChest = State(initialValue: originalChest.wrappedValue) self._editedSleeve = State(initialValue: originalSleeve.wrappedValue) self._editedLength = State(initialValue: originalLength.wrappedValue) case .bottom: self._editedWaist = State(initialValue: originalWaist.wrappedValue) self._editedThigh = State(initialValue: originalThigh.wrappedValue) self._editedRise = State(initialValue: originalRise.wrappedValue) self._editedHem = State(initialValue: originalHem.wrappedValue) self._editedInseam = State(initialValue: originalInseam.wrappedValue) } } var body: some View { NavigationStack { ZStack(alignment: .bottom) { Form { Section { switch realSizeType { case .top: topView case .bottom: bottomView } } } } .navigationTitle("Size") // 移除原来的onAppear回调 } } private func initValue() { // 这个方法可以删除了 } // 以下topView、bottomView代码保持不变 @ViewBuilder var topView: some View { RealSizeInputRowView(title: Top.shoulder.name, amount: $editedShoulder, unit: unit) .focused($focusedField, equals: .shoulder) .onTapGesture { focusedField = .shoulder } RealSizeInputRowView(title: Top.chest.name, amount: $editedChest, unit: unit) .focused($focusedField, equals: .chest) .onTapGesture { focusedField = .chest } RealSizeInputRowView(title: Top.sleeve.name, amount: $editedSleeve, unit: unit) .focused($focusedField, equals: .sleeve) .onTapGesture { focusedField = .sleeve } RealSizeInputRowView(title: Top.length.name, amount: $editedLength, unit: unit) .focused($focusedField, equals: .length) .onTapGesture { focusedField = .length } } @ViewBuilder var bottomView: some View { RealSizeInputRowView(title: Bottom.waist.name, amount: $editedWaist, unit: unit) .focused($focusedField, equals: .waist) .onTapGesture { focusedField = .waist } RealSizeInputRowView(title: Bottom.thigh.name, amount: $editedThigh, unit: unit) .focused($focusedField, equals: .thigh) .onTapGesture { focusedField = .thigh } RealSizeInputRowView(title: Bottom.rise.name, amount: $editedRise, unit: unit) .focused($focusedField, equals: .rise) .onTapGesture { focusedField = .rise } RealSizeInputRowView(title: Bottom.hem.name, amount: $editedHem, unit: unit) .focused($focusedField, equals: .hem) .onTapGesture { focusedField = .hem } RealSizeInputRowView(title: Bottom.inseam.name, amount: $editedInseam, unit: unit) .focused($focusedField, equals: .inseam) .onTapGesture { focusedField = .inseam } } }
方案二:使用@AppStorage持久化编辑值(可选)
如果需要在App重启后也保留输入值,可以用@AppStorage替代@State存储编辑值,这样数据会自动保存到本地:
// 示例:把@State替换为@AppStorage,给每个值指定唯一的存储键 @AppStorage("editedShoulder") private var editedShoulder: Double = 0 @AppStorage("editedChest") private var editedChest: Double = 0 // 其他edited*变量同理替换
这种情况下,即使App重启或后台返回,编辑值也会保留。但注意如果多个页面使用相同的存储键会导致数据冲突,需要确保键的唯一性。
内容的提问来源于stack exchange,提问作者idhun90
相关产品推荐
相关产品推荐

