swiftUI状态管理

@state

用于当前视图的状态管理,@State的属性生命周期和当前视图保持一致

swift 复制代码
struct ContentView: View {
    @State private var isPlaying: Bool = false
    var body: some View {
        VStack {
            Button {
                isPlaying.toggle()
            } label: {
                Image(systemName: isPlaying ? "pause.circle" : "play.circle")
            }
        }
        .padding()
  

@binding

主要用于父子视图之间共享状态

swift 复制代码
// 子视图
struct PlayButton: View {
    
    @Binding var isPlaying: Bool
    
    var body: some View {
        Button(action: {
            self.isPlaying.toggle()
        }) {
            Image(systemName: isPlaying ? "pause.circle" : "play.circle")
        }
    }
}

// 父视图
struct ContentView: View {
    @State private var isPlaying: Bool = false
    var body: some View {
        VStack {
            Text("11111")
            Text("22222")
            PlayButton(isPlaying: $isPlaying)
        }
        .padding()
    }
}

@stateObject 和 @observedObject

先看一个例子:

主视图

点击button会更改视图的showRealName的状态,导致视图刷新

swift 复制代码
struct ContentView: View {
    @State private var showRealName = false
    var body: some View {
        VStack {
            Button("Toggle name") {
                showRealName.toggle()
            }
            Text("current user: \(showRealName ? "Harris" : "yiyi")")
            ScorePlate().padding(.top, 20)
        }
        .padding()
    }
}

ScorePlate

点击button改变model的score属性值

swift 复制代码
class Model: ObservableObject {
    init() {
        print("model created")
    }
    @Published var score: Int = 0
}
swift 复制代码
struct ScorePlate: View {
    
    @ObservedObject var model = Model()
    @State private var niceScore = false
    
    var body: some View {
        VStack {
            Button("+1") {
                model.score += 1
                if model.score > 3 {
                    niceScore = true
                }
                print("model.score = \(model.score)")
            }
            Text("score: \(model.score)")
            Text("Nice? \(niceScore ? "YES" : "NO")")
            ScoreText(model: model).padding(.top, 20)
        }
    }
}

ScoreText: 接收从外部传入的model,根据model中score的值更新文本

swift 复制代码
struct ScoreText: View {
    
    @ObservedObject var model: Model
    
    var body: some View {
        if model.score > 10 {
            return Text("fantastic")
        } else if model.score > 3 {
            return Text("Good")
        } else {
            return Text("mmmmm")
        }
    }
}

当多次点击+1 button时,score增加,ScorePlate和ScoreText都正常更新,但是当点击 Togglename 时,发现model的 init 方法再次执行,意味着model被重置了,score的值也被重置了,ScorePlate和ScoreText的状态都丢失了,这不是期望的结果。

原因:这是因为,和@state 这种底层存储被 SwiftUl"全面接管"的状态不同,@observedobject只是在View和Model之间添加订阅关系,而不影响存储。因此,当ContentView中的状态发生变化,ContentView.body 被重新求值时,ScorePlate就会被重新生成,其中的 model也一同重新生成,导致了状态的"丢失"。

解决办法:在ScorePlate中,把model的修饰符改为:@stateobject

相关推荐
Coder_张三1 小时前
iOS 26 适配
前端·ios·swift
用户38034165882972 小时前
崩溃率从 0.3% 到 0.04%:我们做对的不是修 bug,是让每个崩溃只发生一次
ios·swift
2501_915921435 小时前
详细教程:使用Perfdog工具测量iOS应用的功耗性能与优化方法
android·macos·ios·小程序·uni-app·cocoa·iphone
风雨_5 小时前
RTK (Rust Token Killer) 安装、使用与卸载指南
ios
茶底世界之下6 小时前
夜景暗部要提亮多少?用 Awaking 给雪夜街道留一点层次
ios
黑科技iOS上架6 小时前
cocos游戏ios上架前加固流程(小蟹iOS混淆)
ios·审核·ios混淆·执行程序差异化
东坡肘子8 小时前
当 Build in Public 重新转入地下 -- 肘子的 Swift 周报 #157
人工智能·swiftui·swift
OliverQiu1 天前
开源一个 macOS 小工具:集中管理 ChatGPT 的网络启动配置
macos·chatgpt·swiftui·mac·proxy·codex·dmg
QWsin1 天前
「轻漾」App隐私政策
ios·个人开发