Did you not ask the same question Xcode 12.2, App and simulator crashing during parsing JSON file into array
Your JSON files is still incorrect you are missing { before the first line and } at after the last line, however I would take out the "restaurants":
all together
then make a new Swift file with this in (I called Resaurant)
import Foundation
struct Restaurant: Decodable, Identifiable {
let id: Int
let name: String
let imageName: String
let description: String
let category: String
}
make another new Swift file with in (called Bundle-Decodable)
import Foundation
extension Bundle {
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)")
}
}
}
PS read Paul's on how this is made How to decode JSON from your app bundle the easy way
then make a new SwiftUI View (called RestaurantRowView) with this in
import SwiftUI
struct RestaurantRowView: View {
let restaurant: Restaurant
var body: some View {
HStack {
Image(restaurant.imageName)
.resizable()
.scaledToFit()
.frame(width: 50, height: 50)
.cornerRadius(10)
.shadow(radius: 10)
VStack(alignment: .leading) {
Text(restaurant.name)
.font(.headline)
.bold()
Text(restaurant.description)
.foregroundColor(.secondary)
.multilineTextAlignment(.leading)
}
}
}
}
struct RestaurantRowView_Previews: PreviewProvider {
static let restaurants = Bundle.main.decode([Restaurant].self, from: "Rest.json")
static var previews: some View {
RestaurantRowView(restaurant: restaurants[0])
.previewLayout(.sizeThatFits)
}
}
ps please note the position of static let restaurants
not in the static var previews
then in your RestaurantsView
or ContentView
put this in
import SwiftUI
struct RestaurantsView: View { // if using ContentView then use that here instead of RestaurantView
let restaurants = Bundle.main.decode([Restaurant].self, from: "Rest.json")
var body: some View {
List(restaurants) { restaurant in
RestaurantRowView(restaurant: restaurant)
}
}
}
struct RestaurantsView_Previews: PreviewProvider {
static var previews: some View {
RestaurantsView()
}
}
If you want to look at the Project that tested this with here on GitHub https://github.com/NigelGee/RestaurantsApp
Happy coding