You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI自定义@State:如何完善update方法以模拟原生@State?

模拟SwiftUI的@State属性包装器

我已经实现了一个基础的MyStates属性包装器(遵循DynamicProperty),但update()方法的实现不完整,想知道如何模拟真正的@State,让属性变化时自动触发视图刷新。

原始代码:

@propertyWrapper
struct MyStates:DynamicProperty{
    init(wrappedValue:String){
        UserDefaults.standard.set(wrappedValue, forKey: "myString")
    }
    
    var wrappedValue:String{
        nonmutating set{UserDefaults.standard.set(newValue, forKey: "myString")}
        get{UserDefaults.standard.string(forKey: "myString") ?? ""}
    }
    
    var projectedValue:Binding<String>{
        Binding<String>(
            get:{String(self.wrappedValue)},
            set:{
                self.wrappedValue = $0
        }
        )
    }
    
    func update() {
        print("render again")
    }
}

完整实现方案

要模拟真正的@State,核心是让属性变化时能通知SwiftUI刷新视图。我们可以结合ObservableObject来管理内部状态,同时正确实现DynamicProperty的update方法:

import SwiftUI
import Combine

@propertyWrapper
struct MyState: DynamicProperty {
    // 内部用ObservableObject管理状态变化
    private class StateObserver: ObservableObject {
        @Published var value: String
        
        init(initialValue: String, key: String) {
            // 优先从UserDefaults读取已有值,没有则用初始值
            self.value = UserDefaults.standard.string(forKey: key) ?? initialValue
            // 把初始值同步到UserDefaults(如果之前没有的话)
            if UserDefaults.standard.string(forKey: key) == nil {
                UserDefaults.standard.set(initialValue, forKey: key)
            }
        }
    }
    
    private let key: String
    @StateObject private var observer: StateObserver
    
    init(wrappedValue: String, key: String = "myString") {
        self.key = key
        self._observer = StateObject(wrappedValue: StateObserver(initialValue: wrappedValue, key: key))
    }
    
    var wrappedValue: String {
        get { observer.value }
        nonmutating set {
            observer.value = newValue
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
    
    var projectedValue: Binding<String> {
        $observer.value
    }
    
    func update() {
        // SwiftUI会在视图刷新时调用此方法,这里无需额外操作,@StateObject已自动处理状态订阅
        // 若有自定义需求(如日志、额外状态同步)可在此添加逻辑
    }
}

关键说明

  • 状态订阅:通过内部的StateObserver(遵循ObservableObject)和@Published属性,实现状态变化的自动通知,SwiftUI会感知到@Published的变化并刷新视图。
  • UserDefaults同步:初始化时优先读取已有存储值,修改wrappedValue时同步更新UserDefaults,保证数据持久化。
  • update方法:DynamicProperty的update方法会在视图刷新周期被调用,这里因为@StateObject已处理状态绑定,无需额外逻辑。
  • 投影值:直接返回$observer.value即可得到正确的Binding,无需手动实现Binding的get/set。

使用示例

struct ContentView: View {
    @MyState(wrappedValue: "初始值") var myText
    
    var body: some View {
        VStack {
            Text(myText)
            TextField("输入内容", text: $myText)
        }
        .padding()
    }
}

内容的提问来源于stack exchange,提问作者LiangWang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:15:12