[英]SwiftUI trouble with index out of range
我知道這是一個非常簡單的問題,但我只是堅持使用 atm,所以任何建議都將不勝感激,因為我是 SwiftUI 的新手。
我正在嘗試從 firebase 下載文本並將其渲染到視圖中,但我不斷收到超出范圍的錯誤:
致命錯誤:索引超出范圍:文件 Swift/ContiguousArrayBuffer.swift,第 444 行
代碼如下:
var body: some View{
ZStack {
if fetch.loading == false {
LoadingView()
}
else{
Text(names[0])
.bold()
}
}
.onAppear {
self.fetch.longTask()
}
}
這是獲取內容頁面:
@Published var loading = false
func longTask() {
DispatchQueue.main.asyncAfter(deadline: .now()) {
let db = Firestore.firestore()
db.collection("Flipside").getDocuments { (snapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
return
} else {
for document in snapshot!.documents {
let name = document.get("Name") as! String
let description = document.get("Description") as! String
//name = items[doc]
print("Names: ", name)
print("Descriptions: ", description)
names.append(name)
descriptions.append(description)
}
}
}
self.loading = true
}
}
所以基本上當視圖出現時,在數據下載后從 Firebase 獲取數據,然后顯示menuPage()
直到顯示Loading Data
文本。
歡迎任何幫助!
正如 Rob Napier 提到的,問題是您在填充數組之前訪問數組索引。
我建議對您的代碼進行一些改進。 此外,您可以創建一個結構來將所有屬性保存在一個位置,而不是維護單獨的 arrays ( names
, descriptions
,...)。 這將允許您只為您的項目使用一個數組。
struct Item {
let name: String
let description: String
}
class Fetch: ObservableObject {
@Published var items: [Item] = [] // a single array to hold your items, empty at the beginning
@Published var loading = false // indicates whether loading is in progress
func longTask() {
loading = true // start fetching, set to true
let db = Firestore.firestore()
db.collection("Flipside").getDocuments { snapshot, err in
if let err = err {
print("Error getting documents: \(err)")
DispatchQueue.main.async {
self.loading = false // loading finished
}
} else {
let items = snapshot!.documents.map { document in // use `map` to replace `snapshot!.documents` with an array of `Item` objects
let name = document.get("Name") as! String
let description = document.get("Description") as! String
print("Names: ", name)
print("Descriptions: ", description)
return Item(name: name, description: description)
}
DispatchQueue.main.async { // perform assignments on the main thread
self.items = items
self.loading = false // loading finished
}
}
}
}
}
struct ContentView: View {
@StateObject private var fetch = Fetch() // use `@StateObject` in iOS 14+
var body: some View {
ZStack {
if fetch.loading { // when items are being loaded, display `LoadingView`
LoadingView()
} else if fetch.items.isEmpty { // if items are loaded empty or there was an error
Text("No items")
} else { // items are loaded and there's at least one item
Text(fetch.items[0].name)
.bold()
}
}
.onAppear {
self.fetch.longTask()
}
}
}
請注意,可能不需要通過下標訪問 arrays。 如果只有一個項目並且您嘗試訪問items[1]
,您的代碼仍然會失敗。
相反,您可能可以使用first
來訪問第一個元素:
ZStack {
if fetch.loading {
LoadingView()
} else if let item = fetch.items.first {
Text(item.name)
.bold()
} else {
Text("Items are empty")
}
}
或使用ForEach
顯示所有項目:
ZStack {
if fetch.loading {
LoadingView()
} else if fetch.items.isEmpty {
Text("Items are empty")
} else {
VStack {
ForEach(fetch.items, id: \.name) { item in
Text(item.name)
.bold()
}
}
}
}
此外,如果可能,請避免強制展開選項。 如果snapshot == nil
,代碼snapshot..documents
將終止您的應用程序。 此答案中提供了許多有用的解決方案:
基本問題是您在填充names
數組之前評估names[0]
。如果數組為空,那么您會看到此崩潰。 你可能想要的是這樣的:
Item(title: names.first ?? "", ...)
您過早評估names[0]
的原因是您在獲取實際完成之前調用completed
。 您正在與初始方法調用同步調用它。
也就是說,您始終必須考慮存在連接錯誤或數據為空或數據已損壞的情況。 通常,您應該避免下標.first
(更喜歡 .first 之類的東西),並且當您下標 Arrays 時,您必須首先確保您知道有多少元素。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.