簡體   English   中英

SwiftUI 故障,索引超出范圍

[英]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 ( namesdescriptions ,...)。 這將允許您只為您的項目使用一個數組。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM