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

SwiftUI硬币翻转应用界面更新异常,求正确实现代码

问题解决:SwiftUI硬币翻转应用UI更新滞后修复

合适的提问标题推荐

  • SwiftUI + Core Data 数据更新后UI统计值滞后一步如何解决?
  • 基于Core Data的SwiftUI应用中,如何让UI实时同步数据统计结果?
  • SwiftUI中FetchRequest数据变更后,@State变量无法实时更新的问题处理

修复后的完整代码

import SwiftUI

struct CoinFlip: View {
    
    @State private var saveFailed: Bool = false
    @State private var flipResult: Bool = false
    @State private var justFlipped: Bool = false

    @Environment(\.managedObjectContext) private var coinFlipContext
    
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \FlippedCoin.timeStamp, ascending: true)],
        animation: .default)
    private var flippedCoins: FetchedResults<FlippedCoin>
    
    // 从Core Data直接计算统计值,自动同步UI
    private var flipCount: Int {
        flippedCoins.count
    }
    
    private var headsCount: Int {
        flippedCoins.filter { $0.wasHeads }.count
    }
    
    private var percentHeads: Float {
        guard flipCount > 0 else { return 0 }
        return (Float(headsCount) / Float(flipCount)) * 100
    }
    
    var body: some View {
        VStack {
            Spacer()
            
            Button(action: addItem) {
                Label("Flip", systemImage: "plus")
            }
            
            Button(action: eraseHistory) {
                Label("Erase History", systemImage: "minus")
            }
            
            Spacer()
            
            if justFlipped {
                Text(flipResult ? "You flipped heads!" : "You flipped tails!")
                    .onAppear {
                        // 3秒后自动隐藏翻转结果提示
                        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                            justFlipped = false
                        }
                    }
            }
            
            Spacer()
            
            switch flipCount {
            case 0:
                Text("No coin has been flipped.")
            case 1:
                Text("You have flipped a coin only one time.")
                Text("")
                Text(headsCount > 0 ? "It was heads." : "It was tails.")
            default:
                Text("Coins have been flipped \(flipCount) times.")
                Text("")
                Text("\(Int(percentHeads)) % heads.")
            }
            
            if saveFailed {
                VStack {
                    Text("HA HA!")
                    Text("Something went wrong.")
                    Text("")
                    Text("Your flips were not saved! Too bad.")
                }
                .onAppear {
                    // 3秒后自动隐藏错误提示
                    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                        saveFailed = false
                    }
                }
            }
        }
    }
    
    private func addItem() {
        let rndMin = 0
        let rndMax = 1000
        let randRoll = Int.random(in: rndMin...rndMax)
        flipResult = randRoll >= 500
        
        let newItem = FlippedCoin(context: coinFlipContext)
        newItem.timeStamp = Date()
        newItem.wasHeads = flipResult
        newItem.rndMinimun = Int16(rndMin)
        newItem.rndMaximum = Int16(rndMax)
        newItem.rndValue = Int16(randRoll)
        
        do {
            try coinFlipContext.save()
            justFlipped = true
        } catch {
            saveFailed = true
        }
    }
    
    private func eraseHistory() {
        flippedCoins.forEach(coinFlipContext.delete)
        
        justFlipped = false
        
        do {
            try coinFlipContext.save()
        } catch {
            saveFailed = true
        }
    }
}

private let itemFormatter: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .medium
    return formatter
}()

struct CoinFlip_Previews: PreviewProvider {
    static var previews: some View {
        CoinFlip()
    }
}

问题原因与修复说明

  1. 核心问题:原代码在保存Core Data上下文之前调用test1()统计数据,此时flippedCoins还未包含新添加的记录,导致统计值滞后一步;同时用@State变量存储统计值,无法自动响应Core Data的数据变化。
  2. 修复逻辑:
    • 用计算属性替代@State变量,直接从FetchedResults中计算统计值,Core Data数据更新时计算属性会自动重新计算,UI实时同步。
    • 调整addItem()顺序:先保存上下文,再设置justFlipped,确保新数据已经写入后再触发UI更新。
    • 移除了冗余的test1()方法和隐藏的占位视图,符合SwiftUI响应式设计思想。
  3. 额外优化:给翻转结果和错误提示添加自动消失逻辑,提升用户体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:16:06