首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

SwiftUI在@State chage之后重新呈现for循环内的代码

基础概念

SwiftUI 是苹果公司推出的一个用于构建用户界面的框架,它使用声明式语法来描述用户界面。@StateSwiftUI 中的一个属性包装器,用于跟踪和管理可变状态。当 @State 绑定的值发生变化时,SwiftUI 会自动重新计算视图并更新界面。

相关优势

  1. 声明式语法:开发者只需描述界面的最终状态,而不需要手动管理视图的更新逻辑。
  2. 自动更新:当状态变化时,SwiftUI 自动处理视图的重新渲染,减少了手动编写更新逻辑的需要。
  3. 性能优化SwiftUI 使用了差异计算算法,只更新实际发生变化的部分,提高了性能。

类型与应用场景

  • 类型@State 主要用于跟踪单个值的状态,如 Int, String, Bool 等。
  • 应用场景:适用于任何需要响应状态变化的界面元素,如表单输入、开关按钮、列表项等。

示例代码

假设我们有一个列表,每个列表项都有一个开关按钮,点击按钮会改变对应项的状态,并重新呈现列表。

代码语言:txt
复制
import SwiftUI

struct ContentView: View {
    @State private var items = [Item(name: "Item 1", isActive: false),
                                Item(name: "Item 2", isActive: false),
                                Item(name: "Item 3", isActive: false)]

    var body: some View {
        List(items, id: \.name) { item in
            HStack {
                Text(item.name)
                Spacer()
                Toggle(isOn: $item.isActive) {
                    Text(item.isActive ? "Active" : "Inactive")
                }
            }
        }
    }
}

struct Item: Identifiable {
    let id = UUID()
    let name: String
    var isActive: Bool
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

可能遇到的问题及解决方法

问题:@State 变化后列表没有重新呈现

原因:可能是由于 Item 结构体没有被正确地标记为 Identifiable,或者 id 属性没有唯一标识每个项。

解决方法:确保 Item 结构体实现了 Identifiable 协议,并且每个项都有一个唯一的 id

代码语言:txt
复制
struct Item: Identifiable {
    let id = UUID()  // 确保每个项都有一个唯一的ID
    let name: String
    var isActive: Bool
}

问题:性能问题,列表更新缓慢

原因:如果列表项非常多,每次状态变化都可能导致整个列表重新渲染,影响性能。

解决方法:使用 @ObservedObject@EnvironmentObject 来管理列表数据,并确保只有必要的部分被重新渲染。

代码语言:txt
复制
class ItemViewModel: ObservableObject {
    @Published var items = [Item(name: "Item 1", isActive: false),
                            Item(name: "Item 2", isActive: false),
                            Item(name: "Item 3", isActive: false)]
}

struct ContentView: View {
    @ObservedObject private var viewModel = ItemViewModel()

    var body: some View {
        List(viewModel.items, id: \.name) { item in
            HStack {
                Text(item.name)
                Spacer()
                Toggle(isOn: $item.isActive) {
                    Text(item.isActive ? "Active" : "Inactive")
                }
            }
        }
    }
}

通过这种方式,可以更有效地管理状态和视图的更新,提高应用的性能。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

SwiftUI-数据流

用@State修饰的属性,只要属性改变,SwiftUI 内部会自动的重新计算 View的body部分,构建出View Tree,由于 View 都是结构体,SwiftUI 每次构建这个 View Tree...VS @Binding @State只能在当前修饰的属性改变时会触发UI刷新,所以很适合值类型,因为对值类型里面属性的更新,也会触发整个值类型的重新设置。...不过值类型在传递时会发生复制操作,所以给传递后的值类型即使属性更新了也不会触发最初的传过来的值类型的重新赋值,所以界面并不会刷新,此时需要用@Binding,因为它可以将值类型转为引用类型,这样在传递时...@Published 是 Xcode11 beta5 之后新增的代理属性,此属性如果用在 ObservableObject 内,一旦修饰的属性发送了变化,会自动触发 ObservableObject 的...最终再次呈现给用户,等待下次界面操作 注意 在 SwiftUI 中,开发者只需要构建一个视图可依赖的数据源,保持数据的单向有序流转即可,其他数据和视图的状态同步问题 SwiftUI 帮你管理,所以 ViewController

10.2K20

一段因 @State 注入机制所产生的“灵异代码”

State 注入的优化机制在 SwiftUI 中,对于引用类型,开发者可以通过 @StateObject、@ObservedObject 或 @EnvironmentObject 将其注入到视图中。...即使为新上下文中的视图进行的关联操作是在视图求值操作之前完成的,但由于 n 的变化与关联操作被集中在一个 Render Loop 中,这样会导致在关联之后并不会强制新关联的视图刷新( 关联后,值并没有发生变化...State 声明的,但 show 的变化并不会导致 ContextView 重新更新。...但捕获了视图当前的 n 值 ( n = 1 )点击 Button 后,由于 n 值发生了变化,ContextView 重新求值( 重新解析 DSL 代码 )在重新求值的过程中,.fullScreenCover...Text,让 ContextView 与 n 创建了关联,在 n 变化后,ContextView 进行了重新求值,从而让 fullScreenCover 的闭包捕获了变化后的 n 值,并呈现了预期中的结果

1.9K20
  • SwiftUI 视图的生命周期研究

    在 SwiftUI 内部它会至少创建两种类型的树——类型树、视图值树 类型树 开发者通过创建符合 View 协议的结构体定义想要呈现的用户界面,结构体的 body 属性是一个带有众多泛型参数的庞大类型,...当 State 发生变化后,SwiftUI 会生成一棵新的视图值树(Source of truth 没有发生变化的节点,不会重新计算,直接使用旧值),并同老的视图值树进行比对,SwiftUI 将对其中有变化的部分重新布局渲染...1 和 2 之间切换时,SwiftUI 都会重新创建两个新的实例,并且将旧的实例销毁。...比如在 List 和 LazyVStack 中,Cell 视图在创建之后即使滚动出屏幕不参与布局与渲染,但 SwiftUI 仍会保留这些视图的数据,直到 List 或 LazyVStack 被销毁。...开发者即使不了解文本上述的内容,也可以让 SwiftUI 的代码在日常中发挥出不错的效率。但如果能够对视图的生命周期有更深入的了解,将可以帮助开发者在一些特定的场合提高代码的执行效率。

    4.5K30

    Ask Apple 2022 与 SwiftUI 有关的问答(上)

    然后根据它的焦点状态来定制它的显示样式。希望这对你的设计有用。自从 SwiftUI 3.0 提供了 safeAreaInset 视图修饰器之后,实现问题中的案例将不再是难事。...在使用 environmentObject 的情况下,如何避免创建实例的视图被重新计算Q:如何在避免重新计算顶层视图 body 的情况下,在不同子树的两个子视图之间共享状态( 例如 ObservableObject...对于苹果工程师给予的建议有一点请注意,那就是如果有在父视图中修改该环境对象实例的需求,须确保父视图不会被反复重构( SwiftUI 重新创建视图类型的实例 )。...阅读 SwiftUI 的动画机制[8] 一文,了解更多有关动画的内容。自适应高度 SheetQ:如何在 iOS16 中呈现与动态内容高度相匹配的 Sheet?...提问者应该是想通过在父视图中不断修改 id 的参数值,来重新初始化 State 的值。

    12.3K20

    GeometryReader :好东西还是坏东西?

    在一些复杂的布局场景中,或者在某些设备或系统版本中,布局可能需要经过几轮的协商才能获得最终稳定的结果,尤其是当视图需要依赖 GeometryReader 提供的几何信息来重新确定自己的位置和尺寸时。...,通过 GeometryReader 获取的值可能会使你陷入无尽的循环,从而导致视图的不稳定和性能损失,例如: struct GetSize: View { @State var width:...里子和面子:不同的尺寸数据 在 SwiftUI 中,有一些 modifier 是在布局之后,在渲染层面对视图进行的调整。...由于scaleEffect是在布局之后调整的,因此即使创建一个符合 Layout 协议的布局容器,也无法获知其渲染尺寸。在这种情况下,GeometryReader 就发挥了它的作用。.../ [8] Safely Updating The View State: https://swiftui-lab.com/state-changes/ [9] 用 SwiftUI 的方式进行布局:

    65870

    @State 研究

    本文试图探讨并分析SwiftUI 中 @State的实现方式和运行特征;最后提供了一个有关扩展@State功能的思路及例程。读者需要对SwiftUI的响应式编程有基本概念。...数据(状态)驱动 在SwiftUI中,视图是由数据(状态)驱动的。...类型及作用域图片来自于SwiftUI for Absoloute Beginners 其中@State只能用于当前视图,并且其对应的数据类型为值类型(如果非要对应引用类型的话则必须在每次赋值时重新创建新的实例才可以...@State如何工作的 在分析@State如何工作之前,我们需要先了解几个知识点 属性包装器 作为swift 5.1的新增功能之一,属性包装器在管理属性如何存储和定义属性的代码之间添加了一个分割层。...Binding Binding是数据的一级引用,在SwiftUI中作为数据(状态)双向绑定的桥梁,允许在不拥有数据的情况下对数据进行读写操作。

    3K20

    干货 | 关于SwiftUI,看这一篇就够了

    2.1 Opaque Result Type 新建一个SwiftUI的新项目,会出现如下代码:一个Text展示在body中。...但是,在SwiftUI里面,视图中声明的任何状态、内容和布局,源头一旦发生改变,会自动更新视图,因此,只需要一次布局。在属性前面加上@State关键词,即可实现每次数据改动,UI动态更新的效果。...@State内部是在Get的时候建立数据源与视图的关系,并且返回当前的数据引用,使视图能够获取,在Set方法中会监听数据发生变化、会通知SwiftUI重新获取视图body,再通过Function Builders...用户交互过程中,会产生一个用户的action,从上图可以看出,在SwiftUI中数据的流转过程如下: 该行为触发数据改变,并通过@State数据源进行包装; @State检测到数据变化,触发视图重绘;...在Xcode 11中提供了实时预览和静态预览两项功能,实时预览:代码的修改能够实时呈现在Xcode的预览窗口中;此外,Xcdoe还提供了快捷功能,通过command+鼠标点击组件,可以快速、方便地添加组件和设置组件属性

    10.5K11

    SwiftUI 状态管理系统指南

    例如,这里有一个ProfileView的实现,它使用一个Stage包装属性来跟踪一个用户模型,然后在将上述ProfileEditingView的实例作为工作表呈现时,将该模型传递一个绑定——这将自动同步用户对该原始...观察对象 State和Bingding的共同点是,它们处理的是在SwiftUI视图层次结构本身中管理的值。...除了 "迫使 "我们在代码库中建立一个更明确的依赖关系图之外,原因是一个标有ObservedObject的属性并不意味着对这个属性所指向的对象有任何形式的所有权。...标记为StateObject的属性与ObservedObject的行为完全相同——此外,SwiftUI将确保存储在此类属性中的任何对象不会因为框架在重新渲染视图时重新创建新实例而被意外释放: struct...小结 SwiftUI管理状态的方式绝对是该框架最有趣的方面之一,它可能需要我们稍微重新思考数据在应用中的传递方式——至少在涉及到将被我们的UI直接消费和修改的数据时是这样。

    5.1K20

    SwiftUI 的动画机制

    阅读本文前,读者最好已拥有在 SwiftUI 中使用动画编程的经历,或对 SwiftUI 动画的基本使用方法有一定的了解。可以在 此处获取本文的全部代码[2] SwiftUI 的动画是什么?...SwiftUI 采用了声明式语法来描述不同状态下的 UI 呈现,动画亦是如此。官方文档将 SwiftUI 的动画(Animations)定义为:创建从一个状态到另一个状态的平滑过渡。...将修饰符 animation 放置在正确的位置上 代码一: @State var animated = false VStack { Text("Hello world") ....同所有 SwiftUI 的视图修饰符一样,在代码中所处的位置决定了修饰符的作用对象和范围。 animation 的作用对象仅限于它所在视图层次及该层次的子节点。 上面两段代码没有对错之分。...比如,在出场动画进行中时,将状态 show 恢复成 true ,SwiftUI 将会保留当前的分支状态(不会重新创建视图,参见本文附带的范例)。

    14.8K40

    自定义 SwiftUI 中符号图像的外观

    在 SwiftUI 中使用符号图像非常简单,只需使用 Image 视图和所需符号的系统名称。...这样,父元素内的所有符号图像都会受到影响。调色板调色板模式允许符号以多层呈现,每层具有不同的颜色。这种模式非常适合创建色彩丰富的多层图标。...例如,我们的温度计符号具有白色轮廓,在白色背景上是不可见的。并非所有符号都支持每种呈现模式。图层较少的符号在不同模式下看起来可能相同,分层和调色板模式看起来类似于单色。...示例代码import SwiftUIstruct ContentView: View { @State private var value = 0.5 var body: some...将上述代码粘贴到 ContentView.swift 文件中。运行项目,查看效果。结论在SwiftUI中增强符号图像可以显著改善应用程序的外观和感觉。

    12610

    从用SwiftUI搭建项目说起

    这两张图相信看过苹果官方SwiftUI介绍文档并且跟着写了一遍代码的同学应该不陌生,当然我们的目的不是说这两篇的代码,这个具体的可以到下面连接去查看,我自己跟着写了一遍之后对SwiftUI也是有了一个基本的认识...将整个原有的苹果平台差异部分抽象为 App 和 Scene 部分,可以看到Swift5.1之后在完全无需引入UIKit 的情况下我们就创建了一个多平台的App工程,代码也从原本的基于 UI/NS HostViewController...@State变量使用的,具体的我们会在后面的代码中说的,关于这个@State我在项目Demo中有具体的解释,包括像@bind类型或者是@EnvironmentObject这些关键字我们肯定是得需要学习的...,需要注意的是我们点击item的时候视图切换的绑定状态,基本上在代码注释中我说的比较清楚了,应该能理解的。...当 @State 装饰过的属性发生了变化,SwiftUI 会根据新的属性值重新创建视图 */ @State private var selectedTab = 0 var

    4.5K20

    在 SwiftUI 中创建一个环形 Slider

    环形Slider Slider 控件是一种允许用户从一系列值中选择一个值的 UI 控件。在 SwiftUI 中,它通常呈现为直线上的拇指选择器。...有时将这种类型的选择器呈现为一个圆圈,拇指绕着圆周移动可能会更好。本文介绍如何在 SwiftUI 中定义一个环形的 Slider。...有关默认 Slider 的更多信息,可以参阅 如何在 SwiftUI 中自定义 Slider 中自定义外观的内容。 初始化环形轮廓 从ZStack中的三个圆环开始。...这个 Slider 用于修改进度值,并在圆形滑块上实现足够的代码以使拇指和进度弧响应。当前值显示在环形 Slider 的中心。...可以设置滑块视图的大小,并且滑块按预期工作。可以向控件添加更多参数以设置颜色或圆环内显示的值的格式。 GitHub 上提供了 Circular Slider 的代码。

    3.7K30

    Swift学习之5.3新特性

    多尾随闭包 Swift 5.3 之前即使有多个尾随闭包也只有最后一个能被写成精简的形式,这种写法一个闭包在圆括号内,另一个在外面。新的写法把这些闭包都放在圆括号外面,显得更加简洁。...,Swift 5.3 之后如果不产生循环引用可以省略self.。这个新特性对 SwiftUI 来说非常友好,因为 SwiftUI 中的 View 保存在值类型的结构体中,所以不会发生循环引用。...struct ContentView: View { @State private var count = 1 var body: some View {...Swift 5.3 之后只有在didSet中使用了oldValue参数时,getter 才会被调用。...Info:可以在排查问题时使用。 Notice (default):默认,可以在排查问题时使用。 Error:在程序执行出错时使用。 Fault:在程序出现bug时使用。

    57240

    使用SwiftUI创建万花尺

    为了完成一些真正意义上的绘图工作,我将带您通过创建一个简单的带SwiftUI的spirograph。...我会解释的,但是如果你不感兴趣的话,跳过这一章是完全可以的——这只是为了好玩,这里没有介绍新的Swift或SwiftUI。 我们的算法有四个输入: 内圈的半径。 外圈的半径。...0到我们的终点来画轮盘赌,并放置在精确的X/Y坐标点。...计算循环中给定点的X/Y坐标(称为“theta: θ”)是真正的数学来源,但老实说,我只是把维基百科上的标准方程式转换成Swift——这不是我梦寐以求的记忆!...,但回报即将到来:我们现在可以在视图中使用该形状,添加各种滑块来控制内半径、外半径、距离、数量,甚至颜色: struct ContentView: View { @State private var

    1.2K10

    打造可适配多平台的 SwiftUI 应用

    但是,如果开发者不能理解 SwiftUI 的这个“限制”,并提前做一些准备工作,可能会为之后的多平台开发工作带来一些隐患和增加不必要的工作量。以“电影猎手”的 iPad 版本为例。...:.safeNavigationBarTitleDisplayMode(.inline)如果你打算将应用引入更多的平台,提前准备一些解决兼容性的代码将会极大地改善之后的开发效率。...这种做法不仅可以解决跨平台兼容性问题,还有其他好处:可以改善视图中代码的整洁度(减少条件编译语句的使用)可以改善 SwiftUI 在不同版本之间的兼容性当然,要创建并使用这类代码,前提是开发者必须已经对...对于“电影猎手”当前的状态配置来说,我们可以通过将创建 Store 实例的位置移动到场景内来解决上述问题(将 MovieHunterApp 中与 Store 有关的代码移动到 ContentView 中...当一个场景被创建后,通过 onAppear 里的代码,在 App State 中创建属于它自己的 State 数据,并在场景被删除时,通过 onDisappear 里的代码,将当前场景的 State 清除掉

    3.2K80
    领券