SwiftUI中@State更新后自定义CustomView未同步刷新问题
SwiftUI自定义容器视图嵌套时@State数组更新不刷新问题
问题现象
- 基于Swift + SwiftUI开发应用时,数组类型的
@State属性定义在父视图层级,更新数组元素可正常触发视图响应刷新 - 完全相同的属性与逻辑代码放入自定义容器
CustomView中时,状态更新无法触发UI同步刷新 - 出现问题的
CustomView是仅做布局承载的简单容器视图,逻辑与父视图中可正常运行的代码无差异,仅在嵌套到自定义内部视图时,值更新后UI不会同步变化

复现代码
struct MyItem: Identifiable, Hashable { var text: String var id = UUID() } struct TempView: View { @State var outerItems = [MyItem]() @State var innerItems = [MyItem]() var body: some View { VStack() { ForEach(outerItems) { entry in VStack { Text(entry.text) } } Button(action: { self.outerItems.append(MyItem(text: "Inner Item:\(outerItems.count)")) }) { Text("Add Outer Item") } Divider() CustomView { VStack { ForEach(innerItems) { entry in VStack { Text(entry.text) } } Button(action: { self.innerItems.append(MyItem(text: "Outer Item:\(innerItems.count)")) }) { Text("Add inner Item") } } } } } } struct CustomView<Content: View>: View { // 错误写法:给传入的内容闭包加了@State标记 @State var content: () -> Content var body: some View { content() } }
问题根因
错误点在自定义CustomView的content属性定义:@State是SwiftUI提供给当前视图管理自有、内部状态的属性包装器,被@State标记的属性会被SwiftUI在视图生命周期内缓存持有,仅当属性本身的值变更时才会触发当前视图body重新计算。
而传入的content闭包是父视图构建的视图内容,不属于CustomView自身的内部状态,给它加@State后,SwiftUI会在CustomView首次加载时缓存这个闭包,后续父视图的innerItems状态变更时,CustomView不会重新获取更新后的内容闭包,一直使用首次缓存的旧闭包渲染,自然不会触发UI刷新。
修复方案
删除content属性上错误的@State标记,按照SwiftUI自定义容器的标准写法,用@ViewBuilder标记内容闭包即可:
struct CustomView<Content: View>: View { private let content: () -> Content init(@ViewBuilder content: @escaping () -> Content) { self.content = content } var body: some View { content() } }
修改后外部传入的内容闭包会跟随父视图的状态变化自动重新构建,点击内部添加按钮即可正常触发列表刷新。
注意:
@State、@StateObject这类状态包装器仅用于修饰视图自身所有、不依赖外部传入的状态值,外部传入的视图构建闭包不要使用状态包装器修饰。
内容的提问来源于stack exchange,提问作者user8719510
相关产品推荐
相关产品推荐

