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

SwiftUI实现APP界面JSON数据每15秒自动更新 新手求助

解决SwiftUI中JSON数据定时刷新与Float显示问题

嘿,作为Swift新手从Android转过来,遇到这种适配问题太正常了!我来帮你搞定这两个核心需求:每15秒自动更新数据,以及正确显示Float类型的数值。

一、先搞定Float类型的显示问题

你现在直接拼接Float值到Text里,会因为浮点数的精度问题出现多余的小数位(比如98.4可能显示成98.4000015...)。解决这个问题有两种简单的方式:

方式1:使用格式化字符串

直接在Text里用String(format:)来指定小数位数:

Text("ONE: \(String(format: "%.1f", user?.ONE_R ?? 0))")

这里的%.1f表示保留1位小数,你可以根据需求改成%.2f保留两位,以此类推。

方式2:用SwiftUI的NumberFormatter

如果需要更统一的格式化规则,可以定义一个NumberFormatter:

private let floatFormatter: NumberFormatter = {
    let formatter = NumberFormatter()
    formatter.numberStyle = .decimal
    formatter.minimumFractionDigits = 1
    formatter.maximumFractionDigits = 1
    return formatter
}()

然后在Text里使用:

Text("ONE: \(floatFormatter.string(from: NSNumber(value: user?.ONE_R ?? 0)) ?? "0")")

二、实现每15秒自动刷新数据(类似Android的Handler)

在SwiftUI里,我们可以用Timer.TimerPublisher来实现定时任务,这比传统的Timer更贴合SwiftUI的响应式架构。具体步骤如下:

  1. 先导入Combine框架(用来处理定时器的订阅):
import Combine
  1. 在视图里添加一个定时器的订阅对象,用来管理定时器的生命周期:
@State private var timer: AnyCancellable?
  1. 修改onAppear方法,启动定时器并定时调用loadD:
.onAppear {
    loadD() // 首次加载数据
    // 每15秒触发一次刷新
    timer = Timer.publish(every: 15, on: .main, in: .common)
        .autoconnect()
        .sink { _ in
            loadD()
        }
}
  1. 记得在视图消失时取消定时器,避免内存泄漏:
.onDisappear {
    timer?.cancel()
}

完整修改后的代码

把上面的修改整合到你的代码里,最终版本如下:

import SwiftUI
import Combine

struct DATA: Codable {
    let ONE_R: Float
    let TWO_R: Float
}

struct AllTEC: View {
    @State var user: DATA?
    @State private var timer: AnyCancellable?
    
    // 可选:统一的浮点数格式化器
    private let floatFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.minimumFractionDigits = 1
        formatter.maximumFractionDigits = 1
        return formatter
    }()
    
    var body: some View {
        VStack(spacing: 20) {
            // 方式1:用String(format)快速格式化
            Text("ONE: \(String(format: "%.1f", user?.ONE_R ?? 0))")
            // 方式2:用NumberFormatter实现统一格式
            Text("TWO: \(floatFormatter.string(from: NSNumber(value: user?.TWO_R ?? 0)) ?? "0")")
        }
        .onAppear {
            loadD()
            // 启动15秒定时刷新
            timer = Timer.publish(every: 15, on: .main, in: .common)
                .autoconnect()
                .sink { _ in
                    loadD()
                }
        }
        .onDisappear {
            timer?.cancel() // 视图销毁时取消定时器
        }
    }
}

extension AllTEC {
    func loadD() {
        guard let url = URL(string: "https://symbiosys-a415a.firebaseio.com/DATA.json") else {
            print("Invalid URL")
            return
        }
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                print("Error fetching data: \(error.localizedDescription)")
                return
            }
            guard let data = data else {
                print("No data received")
                return
            }
            do {
                let decodedData = try JSONDecoder().decode(DATA.self, from: data)
                DispatchQueue.main.async {
                    self.user = decodedData
                }
            } catch {
                print("Failed to decode data: \(error.localizedDescription)")
            }
        }
        task.resume()
    }
}

struct AllTEC_Previews: PreviewProvider {
    static var previews: some View {
        AllTEC()
    }
}

额外说明

  • 用Timer.TimerPublisher的好处是它自动绑定主线程,通过autoconnect()可以直接启动,不用手动管理定时器的启停逻辑。
  • 一定要在onDisappear里取消定时器,不然视图销毁后定时器还会继续触发网络请求,造成不必要的资源浪费和内存泄漏。
  • 如果觉得Combine的方式有点复杂,也可以用传统的Timer.scheduledTimer,但要记得在主线程更新UI,并且在视图消失时调用timer.invalidate()。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 20:37:49