I am using Firebase to append a String of data for an Array. I would then like to display this data on the screen. The view on the screen is a List and each Post is looking at a different part of the Array (example; postName[0] vs. postName[1].
My problem is that as soon as the screen loads, the data has not completely loaded from the cloud yet and therefore the Array is empty. This causes the app to crash saying that "Index out of range" since there is nothing in an array that a Text box is trying to read from.
The Array receives data from Firebase and if the data arrives fast enough no issue occurs, however, sometimes the data does not come fast enough and crashes saying index not in range.
Is there anything I can set up to not load the Text field until the data has finished loading?
Code provided:
List(fetchPostModel.postsNearby, id: \.self) { post in
ZStack {
if !fetchPostModel.postName.isEmpty { Text(fetchPostModel.postName[Int(post) ?? 0])
.font(.title)
.bold()
.padding()
} else { Text("Loading...").font(.title).bold().padding() }
}
.onAppear {
fetchFromCloud(postNumber: fetchFromCloud.postNumber[Int(post) ?? 0])
}
}
CodePudding user response:
To prevent the "Index out of range" you can unwrap the property first to avoid the Int(post) ?? 0
if !fetchPostModel.postName.isEmpty {
if let postIndex = post {
Text(fetchPostModel.postName[Int(postIndex)])
.font(.title)
.bold()
.padding()
}
} else { Text("Loading...").font(.title).bold().padding() }
CodePudding user response:
you can create one extension for that
extension Collection where Indices.Iterator.Element == Index {
public subscript(safe index: Index) -> Iterator.Element? {
return (startIndex <= index && index < endIndex) ? self[index] : nil
}
}
Now it can be applied universally across different collections
Example:
[1, 2, 3][safe: 4] // Array - prints 'nil'
(0..<3)[safe: 4] // Range - prints 'nil'
In your problem, you can use like that
List(fetchPostModel.postsNearby, id: \.self) { post in
ZStack {
if let currentPostName = fetchPostModel.postName[safe: post] {
Text(currentPostName)
.font(.title)
.bold()
.padding()
} else {
Text("Loading...").font(.title).bold().padding()
}
}
.onAppear {
fetchFromCloud(postNumber: fetchFromCloud.postNumber[Int(post) ?? 0])
}
}