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的响应式架构。具体步骤如下:
- 先导入Combine框架(用来处理定时器的订阅):
import Combine
- 在视图里添加一个定时器的订阅对象,用来管理定时器的生命周期:
@State private var timer: AnyCancellable?
- 修改
onAppear方法,启动定时器并定时调用loadD:
.onAppear { loadD() // 首次加载数据 // 每15秒触发一次刷新 timer = Timer.publish(every: 15, on: .main, in: .common) .autoconnect() .sink { _ in loadD() } }
- 记得在视图消失时取消定时器,避免内存泄漏:
.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
相关产品推荐
相关产品推荐

