我构建了一个 iPhone 应用程序来显示华盛顿特区地铁的列车时刻表和系统警报数据。
我有一个 Firebase 实时数据库,其中存储从 WMATA API 中提取的数据,我的应用程序异步加载数据并向用户显示。
应用程序运行正常,但有时界面有点不稳定,刷新轮在居中之前快速向左跳动,页面在数据加载之前快速闪烁空白。我认为这与我在刷新实际数据之前刷新界面的方式有关,这似乎是“正确”的做事方式,但使应用程序看起来比我想要的更加脱节。如果我能弄清楚如何防止刷新轮跳来跳去,我可能会没事,但我也很好奇是否有一个好的方法来防止加载 UI 元素(在本例中为“所有推文”)链接)直到异步数据加载完毕。
这是我的应用程序中的“警报”选项卡,在页面完全加载之前,它显示了跳跃的界面和不居中的“所有推文”链接的快速闪烁:
这是我尝试编写用于显示此页面的代码的更简单版本,该代码在页面加载时将来自 Firebase 的警报作为任务异步加载。
import SwiftUI
import FirebaseDatabase
class AlertListDebug: ObservableObject {
@Published var alerts = [String:[String:Any]]()
//Initializers
init() {
}
//Get data asynchronously
@MainActor
func getAlertsDataDebug(refAlertsRaw: DatabaseReference!, officialTwitter: String) async {
self.alerts = [:]
//Generate query
var query: DatabaseQuery
query = refAlertsRaw.child("alerts").child("raw_" + officialTwitter)
//Query data
query.observeSingleEvent(of: .value) { snapshot in
if(!(snapshot.value is NSNull)) {
let dict = snapshot.value as! [String: Any]
for element in dict {
let key = element.key
let alertRaw = element.value as! [String: Any]
let alert = ["lines": alertRaw["Line"]!, "text": alertRaw["Text"]!]
//Add alert element to list
self.alerts[key] = alert
}
}
}
}
}
struct AlertsViewDebug: View {
@StateObject var alertList = AlertListDebug()
//Variable tracking whether official or Twitter alerts are being shown
@State var officialTwitter = "official"
//Create database reference
var refAlertsRaw: DatabaseReference! = Database.database().reference()
var body: some View {
VStack(alignment: .leading, spacing: 0){
//Official and Twitter alert source buttons
HStack {
Button(action: {
officialTwitter = "official";
Task {
await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw, officialTwitter: officialTwitter)
}
}) {
Text("Official Alerts")
}
Spacer()
Button(action: {
officialTwitter = "twitter";
Task {
await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw, officialTwitter: officialTwitter)
}
}) {
Text("Twitter Feed")
}
}
//Display list of alerts
ScrollView {
VStack(spacing: 0) {
if(alertList.alerts.count > 0) {
ForEach(alertList.alerts.keys.sorted(), id: \.self) {alertKey in
Text(alertKey)
.font(.system(size: 16))
.foregroundColor(.black)
.frame(width: 320)
}
}
}.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(.black, lineWidth: 1)
)
.padding(.vertical, 5)
if(officialTwitter == "twitter") {
//Browser link to Twitter feed
Text("All Tweets")
}
}.task {
await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw, officialTwitter: officialTwitter)
}.refreshable {
await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw, officialTwitter: officialTwitter)
}
Spacer()
}.navigationTitle("Alerts")
.navigationBarTitleDisplayMode(.inline)
}
}
如果我的做法有误,请告诉我 - 谢谢!
显然这是由您在alertList上获取更新引起的,该更新速度非常快并导致ui刷新(https://github.com/pointfreeco/swift-composable-architecture/discussions/2542)。
您可以使用睡眠来解决它,但这不是理想的解决方案。 我也有类似的问题,还没解决。
.refreshable {
try? await Task.sleep(nanoseconds: 1_000_000_000)
await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw,officialTwitter: officialTwitter)
}