I work on an app that displays random quotes from the JSON Bundle.
I have an issue where I cannot refresh the displayed quote. Text(...) populates once the app loads and that's it. I'd appreciate suggestions on how can I refresh the quote and the author on the button tap.
Here is the minimum reproducible code:
JSON Structure:
[
{
"text": "Genius is one percent inspiration and ninety-nine percent perspiration.",
"author": "Thomas Edison"
},
{
"text": "You can observe a lot just by watching.",
"author": "Yogi Berra"
}
]
My struct:
struct Quote: Codable{
var text: String?
var author: String?
}
Here's the Bundle extension I am using:
func decode<T: Decodable>(_ type: T.Type, from file: String, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> T {
guard let url = self.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = dateDecodingStrategy
decoder.keyDecodingStrategy = keyDecodingStrategy
do {
return try decoder.decode(T.self, from: data)
} catch DecodingError.keyNotFound(let key, let context) {
fatalError("Failed to decode \(file) from bundle due to missing key '\(key.stringValue)' not found – \(context.debugDescription)")
} catch DecodingError.typeMismatch(_, let context) {
fatalError("Failed to decode \(file) from bundle due to type mismatch – \(context.debugDescription)")
} catch DecodingError.valueNotFound(let type, let context) {
fatalError("Failed to decode \(file) from bundle due to missing \(type) value – \(context.debugDescription)")
} catch DecodingError.dataCorrupted(_) {
fatalError("Failed to decode \(file) from bundle because it appears to be invalid JSON")
} catch {
fatalError("Failed to decode \(file) from bundle: \(error.localizedDescription)")
}
}
}
And a ContentView:
struct ContentView: View {
let quotes = Bundle.main.decode([Quote].self, from: "quotes.json")
var quote : Quote { quotes.randomElement()! }
var body: some View {
VStack {
VStack {
Text(quote.text!)
.font(.system(.title3))
Text(quote.author!)
.font(.system(.title3))
Button("refresh") {
quote = quotes.randomElement()! //-> Error here: Cannot assign to property: 'quote' is a get-only property
}
}
}
}
}