pass values dynamically for network request - ios

I have to pass the value of movie.id which is received from a View which is called ReviewView.
I need to pass the movie.id value received in this view to ReviewFetcher and then make a network request using that movie.id. As of now I have hard coded the movie id in ReviewFetcher but I require this to be received from ReviewView and then make a request and then update the list in ReviewView.
Below is the Code:-
ReviewFetcher.swift
import Foundation
import Alamofire
import SwiftUI
class ReviewObserver: ObservableObject {
#Published var review = ReviewArray(id: 1, page: 9, results: [])
// #State var movieID:Int
init() {
// self.movieID = movieID
getReviews(movieID : 181812)
}
func getReviews(movieID:Int) {
//self.review.results.removeAll()
let reviewURL = "https://api.themoviedb.org/3/movie/"+String(movieID)+"/reviews?api_key=a18f578d774935ef9f0453d7d5fa11ae&language=en-US&page=1"
Alamofire.request(reviewURL)
.responseJSON { response in
if let json = response.result.value {
if (json as? [String : AnyObject]) != nil {
if let dictionaryArray = json as? Dictionary<String, AnyObject?> {
let json = dictionaryArray
if let id = json["id"] as? Int,
let page = json["page"] as? Int,
let results = json["results"] as? Array<Dictionary<String, AnyObject?>> {
for i in 0..<results.count {
if let author = results[i]["author"] as? String,
let content = results[i]["content"] as? String,
let url = results[i]["url"] as? String {
let newReview = ReviewModel(author: author,
content: content,
url: url)
self.review.results.append(newReview)
}
}
}
}
}
}
}
}
}
ReviewView.swift
import SwiftUI
struct ReviewsView: View {
#State var movie: MovieModel
#Binding var reviews:[ReviewModel]
#ObservedObject var fetcher = ReviewObserver()
var body: some View {
VStack(alignment:.leading) {
Text("Review")
.font(.largeTitle)
.bold()
.foregroundColor(Color.steam_rust)
.padding(.leading)
Divider()
// Text(String(fetcher.movieID))
List(fetcher.review.results) { item in
VStack(alignment:.leading) {
Text("Written by : "+item.author)
.font(.body)
.bold()
.padding(.bottom)
Text(item.content)
.font(.body)
.lineLimit(.max)
}
}
}
}
}
MovieModel.swift
import Foundation
import SwiftUI
import Combine
struct MovieArray: Codable {
var page: Int = 0
var total_results: Int = 0
var total_pages: Int = 0
var results: [MovieModel] = []
}
struct MovieModel: Codable, Identifiable {
var id : Int
var original_title: String
var title: String
var original_language:String
var overview: String
var poster_path: String?
var backdrop_path: String?
var popularity: Double
var vote_average: Double
var vote_count: Int
var video: Bool
var adult: Bool
var release_date: String?
}

Remove the init() of your ReviewObserver class. and then call getReviews method in .onAppear modifier of your VStack. The idea of what you need:
class ReviewObserver: ObservableObject {
#Published var review = ReviewArray(id: 1, page: 9, results: [])
func getReviews(movieID:Int) {
//you block,, anything you wanna do with movieID.
//Assume you are going to change 'review' variable
}
}
struct ReviewsView: View {
#State var movie:MovieModel
#Binding var reviews:[ReviewModel]
#ObservedObject var fetcher = ReviewObserver()
var body: some View {
VStack(alignment:.leading){
Text("Review")
Divider()
Text(String(fetcher.movieID))
List(fetcher.review.results)
{
item in
VStack(alignment:.leading){
Text("Written by : "+item.author)
}
}.onAppear {
self.fetcher.getReviews(movieID: movie.id)
}
}
}

Related

Firebase is not saving the data - swiftui

I have a problem that Firebase not saving the data and it shows like that :
enter image description here
First I created a model :
struct Box: Identifiable, Hashable, Codable {
#DocumentID var id: String?
var boxName: String
var boxSize: String
enum CodingKeys: String, CodingKey {
case id
case boxName
case boxSize
}
var dictionary: [String: Any] {
let data = (try? JSONEncoder().encode(self)) ?? Data()
return (try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any]) ?? [:]
}
}
Then I created ViewModel:
class BoxViewModel: ObservableObject {
#Published var box: Box
private var db = Firestore.firestore()
init(box: Box = CashBox(boxName: "", boxSize: "")) {
self.box = box
}
private func addNewBox(_ box: Box){
do {
print("the name \(box.boxName)")
let _ = db.collection("Box")
.addDocument(data: box.dictionary)
}
}
func addBox() {
self.addNewBox(box)
}
func setBoxData(boxName: String, boxSize: String){
self.box.boxName = boxName
self.box.boxSize = boxSize
}
}
Finally here is the view:
struct CashBoxView: View {
#State var boxName = ""
#State var boxSize = ""
#EnvironmentObject var boxViewModel: BoxViewModel
var body: some View {
Text("Enter box name")
TextField("", text: $boxName)
Text("Enter box size")
TextField("", text: $boxSize)
Button( action: {
boxViewModel.setBoxData(boxName: boxName, boxSize: boxSize)
boxViewModel.addBox()
}) {
Text("Done")
}
}
First I thought that the problem is the box is empty but when I tried to print the box name print("the name \(box.boxName)") and printed it
is the problem the the viewModel is #EnvironmentObject ? or what is the problem ?
Thank you,

Sorting items by date. And adding numbers from today

This is Model and View Model. I am using UserDefaults for saving data.
import Foundation
struct Item: Identifiable, Codable {
var id = UUID()
var name: String
var int: Int
var date = Date()
}
class ItemViewModel: ObservableObject {
#Published var ItemList = [Item] ()
init() {
load()
}
func load() {
guard let data = UserDefaults.standard.data(forKey: "ItemList"),
let savedItems = try? JSONDecoder().decode([Item].self, from: data) else { ItemList = []; return }
ItemList = savedItems
}
func save() {
do {
let data = try JSONEncoder().encode(ItemList)
UserDefaults.standard.set(data, forKey: "ItemList")
} catch {
print(error)
}
}
}
and this is the view. I am tryng too add new item and sort them by date. After that adding numbers on totalNumber. I tried .sorted() in ForEach but its not work for sort by date. and I try to create a func for adding numbers and that func is not work thoo.
import SwiftUI
struct ContentView: View {
#State private var name = ""
#State private var int = 0
#AppStorage("TOTAL_NUMBER") var totalNumber = 0
#StateObject var VM = ItemViewModel()
var body: some View {
VStack(spacing: 30) {
VStack(alignment: .leading) {
HStack {
Text("Name:")
TextField("Type Here...", text: $name)
}
HStack {
Text("Number:")
TextField("Type Here...", value: $int, formatter: NumberFormatter())
}
Button {
addItem()
VM.save()
name = ""
int = 0
} label: {
Text ("ADD PERSON")
}
}
.padding()
VStack(alignment: .leading) {
List(VM.ItemList) { Item in
Text(Item.name)
Text("\(Item.int)")
Text("\(Item.date, format: .dateTime.day().month().year())")
}
Text("\(totalNumber)")
.padding()
}
}
}
func addItem() {
VM.ItemList.append(Item(name: name, int: int))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
First of all please name variables always with starting lowercase letter for example
#Published var itemList = [Item] ()
#StateObject var vm = ItemViewModel()
To sort the items by date in the view model replace
itemList = savedItems
with
itemList = savedItems.sorted{ $0.date < $1.date }
To show the sum of all int properties of the today items add a #Published var totalNumber in the view model and a method to calculate the value. Call this method in load and save
class ItemViewModel: ObservableObject {
#Published var itemList = [Item] ()
#Published var totalNumber = 0
init() {
load()
}
func load() {
guard let data = UserDefaults.standard.data(forKey: "ItemList"),
let savedItems = try? JSONDecoder().decode([Item].self, from: data) else { itemList = []; return }
itemList = savedItems.sorted{ $0.date < $1.date }
calculateTotalNumber()
}
func save() {
do {
let data = try JSONEncoder().encode(itemList)
UserDefaults.standard.set(data, forKey: "ItemList")
calculateTotalNumber()
} catch {
print(error)
}
}
func calculateTotalNumber() {
let todayItems = itemList.filter{ Calendar.current.isDateInToday($0.date) }
totalNumber = todayItems.map(\.int).reduce(0, +)
}
}
In the view delete the #AppStorage line because the value is calculated on demand and replace
Text("\(totalNumber)")
with
Text("\(vm.totalNumber)")

SwiftUI why doesn't my view update once this object property changes?

#ObservedObject var vm: PlayerViewModel
var body : some View {
Button("Test"){
Task{
await vm.getPlayer(username: username)
switch vm.state{
case .success(var player):
let docRef = vm.db.collection("players").document(player.displayname)
docRef.getDocument {document, error in
if let document = document, document.exists {
print("document exists")
player.todayFinalKills = document["todayFinalKills"] as? Int
print(player.todayFinalKills ?? 0)
}
}
}
}
So I just have some firestore database here(not really relevant to the question I don't think) I'm calling some function, I check the state of some enum and then check if the document exists, if it exists I change one property in the associated data of the enum. This is what this prints:
So it does seem that the property is getting updated in the player object for sure but then I have another view with a List
struct DailyView: View {
#ObservedObject var vm: PlayerViewModel
var body: some View {
List{
Text("\(player.todayFinalKills ?? 0)")
}
}
}
But this view always has a zero, implying that this still thinks todayFinalKills is nil? If it literally prints it out as 8291 why is this happening? I was thinking maybe if I switch on a enum like this and extract the associated data maybe it creates a copy but I wasn't able to find much information about this online. Can anyone help me figure out why this is happening? I am passing the same ViewModel into all these views.
Edit: PlayerViewModel.swift
import FirebaseFirestore
import Foundation
#MainActor
class PlayerViewModel: ObservableObject{
enum PlayerState {
case na
case loading
case success(data: Player)
case failed(error : Error)
}
var db = Firestore.firestore()
#Published private(set) var state: PlayerState = .na
private let service: PlayerService
init(service: PlayerService)
{
self.service = service
}
func getPlayer(username: String) async {
state = .loading
do{
let uuid = try await service.fetchUUID(username: username)
let player = try await service.fetchPlayer(uuid: uuid)
state = .success(data: player)
}
catch{
print(error)
state = .failed(error: error)
}
}
}
DailyView.swift
import SwiftUI
struct DailyView: View {
#ObservedObject var vm: PlayerViewModel
var body: some View {
switch vm.state{
case .success(let player):
List{
Text("\(player.todayFinalKills ?? 0)")
}
default:
EmptyView()
}
}
}
struct DailyView_Previews: PreviewProvider {
static var previews: some View {
DailyView(vm: PlayerViewModel(service: PlayerService()))
}
}
LoginView.swift
struct LoginView: View {
#ObservedObject var vm : PlayerViewModel
#State private var username = ""
#State private var profileLoaded = false
private var searchAllowed : Bool{
if(username.count>2)
{
return false
}
return true
}
var body: some View {
NavigationView{
ZStack{
VStack{
Button{
Task{
await vm.getPlayer(username: username)
switch vm.state{
case .success(var player):
let docRef = vm.db.collection("players").document(player.displayname)
docRef.getDocument {document, error in
if let document = document, document.exists {
player.todayFinalKills = document["todayFinalKills"] as? Int
print(player.todayFinalKills ?? 0)
}
else{
let stats : [String : Int] = [
"todayFinalKills": player.stats.Bedwars?.final_kills_bedwars ?? 0,
"todayFinalDeaths" : player.stats.Bedwars?.final_deaths_bedwars ?? 0,
"todayBedwarsWins" : player.stats.Bedwars?.wins_bedwars ?? 0,
"todayBedwarsLosses" : player.stats.Bedwars?.losses_bedwars ?? 0,
"todayTntRunLosses" : player.stats.TNTGames?.deaths_tntrun ?? 0,
"todayTntRunWins" : player.achievements.tntgames_tnt_run_wins ?? 0,
]
vm.db.newPlayerDocument(data: stats, username: player.displayname, uuid: player.uuid)
}
}
profileLoaded = true
default:
print("default")
}
}
} label:
{
ZStack{
RoundedRectangle(cornerRadius: 5)
.fill(.gray)
.frame(width: 200, height: 50)
Text("Search")
.foregroundColor(.white)
}
}
Model.swift
struct Player : Codable, Hashable, Equatable{
static func == (lhs: Player, rhs: Player) -> Bool {
lhs.uuid == rhs.uuid
}
// so a player contains many objects, like stats, achievements, etc
var stats: Stats
var achievements: Achievements
var displayname: String
var uuid : String
var networkExp: Int
var knownAliases : [String]
var karma: Int
var newPackageRank : String? //this could be MVP_PLUS
var rankPlusColor : String? //this could be LIGHT_PURPLE
//daily statistics for the player.
**var todayFinalKills : Int?**
var todayBedwarsLosses : Int?
var todayBedwarsWins: Int?
var todayFinalDeaths: Int?
var todayTntRunWins: Int?
var TodayTntRunLosses: Int?
//

Firebase #DocumentID property wrapper not working

I'm trying to update certain values in a specific Firebase document, however, whenever the code fires, I get the error:
[FirebaseFirestore][I-FST000001] WriteStream (7fc6c510be38) Stream error: 'Not found: No document to update: projects/htg-inspection/databases/(default)/documents/Projects/365A2F53-CB38-47A6-93C3-7D6DA14038D9
Based on the response it would seem that the Id I get back from my data struct is different from the document ID that I'm trying to update. I assumed that the #DocumentID property wrapper is supposed to solve this, or am I doing/not doing something correctly/incorrectly?
These are the corresponding DocumentIDs and what I'm getting back are some random strings (assumingly from the Swift's UUID initializer)
My Projects Data Struct:
import Foundation
import FirebaseFirestoreSwift
import FirebaseFirestore
import Firebase
struct ProjectsData: Identifiable, Codable{
#DocumentID var id: String? = UUID().uuidString
var title: String
var client: String
var description: String
var inspections: [InspectionsData]
enum CodingKeys: String, CodingKey{
case id
case title
case client
case description
case inspections
}
}
Sub-Collection:
struct InspectionsData: Identifiable, Codable {
var id = UUID()
var category: Category
var trade: String
var inspectionDate: Date
var dueDate: Date
var assigned: Bool
var location: String
var images: [InspectionImages]
var checklists: [ChecklistsData]
var dateToString: String{
let formatter = DateFormatter()
formatter.dateFormat = "MMMM dd, YYYY "
return formatter.string(from: inspectionDate)
}
var dueDateToString: String{
let formatter = DateFormatter()
formatter.dateFormat = "MMMM dd, YYYY "
return formatter.string(from: dueDate)
}
}
struct ChecklistsData: Identifiable, Codable{
var id = UUID()
var question: String
var hasPassed: Bool
var hasFailed: Bool
var isnotApplicable: Bool
}
enum ChecklistCodingKeys: String, CodingKey{
case id
case question
case hasPassed
case hasFailed
case isnotApplicable
}
My View Model:
class ProjectsViewModel: ObservableObject {
#Published var projects = [ProjectsData]()
#Published var inspectionData = [InspectionsData]()
#Published var assignedProjects: [AssignedProjectsModel] = []
#Published var retrievePhotos = [UIImage]()
#Published var inspectionImages = [InspectionImages]()
#Published var showImageViewer = false
#Published var selectedImageID: String = ""
#Published var checklists = [ChecklistsData]()
#Published var hasPassed = false
#Published var hasFailed = false
#Published var isnotApplicable = false
func updateChecklist(_ checklist: ProjectsData, hasPassed: Bool, hasFailed: Bool, isnotApplicable: Bool) {
if let documentId = checklist.id {
db.collection("Projects").document(documentId).updateData(["checklists" : ["hasPassed" : hasPassed, "hasFailed" : hasFailed, "isnotApplicable" : isnotApplicable]]) {
error in
if let error = error {
print(error.localizedDescription)
} else {
print("Document has been updated")
}
}
}
}
}
The View that I'm trying to update the database from:
struct ChecklistComponent: View {
#State var hasPassed: Bool
#State var hasFailed: Bool
#State var isnotApplicable: Bool
#ObservedObject var checklistvm = ProjectsViewModel()
var documentID: ProjectsData
var checklistItem: String = ""
var question: String = ""
var body: some View {
VStack{
HeaderOne(text: question, size: 16)
Spacer()
HStack{
ChecklistButton(text: "Pass", textColor: hasPassed ? "#00AA97" : "#696969", buttonColor: hasPassed ? "#B0EFE8" : "#DBDBDB",
action: {
hasPassed.toggle()
hasFailed = false
isnotApplicable = false
checklistvm.updateChecklist(documentID, hasPassed: hasPassed, hasFailed: hasFailed, isnotApplicable: isnotApplicable)
})
ChecklistButton(text: "Fail", textColor: hasFailed ? "#AA0000" : "#696969", buttonColor: hasFailed ? "#EFB0B0" : "#DBDBDB",
action: {
hasFailed.toggle()
hasPassed = false
isnotApplicable = false
checklistvm.updateChecklist(documentID, hasPassed: hasPassed, hasFailed: hasFailed, isnotApplicable: isnotApplicable)
})
ChecklistButton(text: "N/A", textColor: isnotApplicable ? "#89AA00" : "#696969", buttonColor: isnotApplicable ? "#EDEFB0" : "#DBDBDB",
action: {
isnotApplicable.toggle()
hasFailed = false
hasPassed = false
checklistvm.updateChecklist(documentID, hasPassed: hasPassed, hasFailed: hasFailed, isnotApplicable: isnotApplicable)
})
}
}
.padding()
.frame(width: UIScreen.main.bounds.width-30 ,height: 161)
.background(.white)
.cornerRadius(31)
}
}
Of course this is a lot of code and I can't share the entire project, but hopefully this can give enough context to lend your assistance.
Using #FirestoreQuery wrapper:
import SwiftUI
import Firebase
import FirebaseFirestore
import FirebaseFirestoreSwift
struct HomeView: View {
#State var searchable = ""
#State var navtoView = false
#State var showLogoutdialog = false
#ObservedObject var homevm = HomeViewModel()
var auth = AuthService()
#Environment(\.presentationMode) var presentationmode
#State var firstname = ""
#ObservedObject var projectvm = ProjectsViewModel()
#State var selectedProject: ProjectsData?
#FirestoreQuery(collectionPath: "Projects") var projects: [ProjectsData]
var body: some View {
NavigationView{
ScrollView(.vertical){
Spacer()
.height(70)
HeaderComponent(firstname: users.firstName)
SearchBar(searchText: $searchable)
.padding(.bottom)
VStack {
ForEach(projects, id: \.id) { item in
ProjectFeedCard(projectTitle: item.title, client: item.client)
.onTapGesture {
self.selectedProject = item
navtoView.toggle()
}
}
}
//MARK: NavigationLinks
NavigationLink(destination:ProjectView(inspections: selectedProject?.inspections ?? [], projectTitle: selectedProject?.title ?? "" , client: selectedProject?.client ?? "",description: selectedProject?.description ?? "", documentID: selectedProject ?? ProjectsData(title: "", client: "", description: "", inspections: []), checklists: []) , isActive: $navtoView){
EmptyView()
}
Spacer()
CustomButton(action: {showLogoutdialog.toggle()}, buttonText: "Log Out", buttonColor: .accentColor)
.padding()
.confirmationDialog("Are you sure?", isPresented: $showLogoutdialog, titleVisibility: .visible){
Button("Sign Out", role: .destructive){
homevm.logOutApp()
presentationmode.wrappedValue.dismiss()
}
}
.onAppear{
projectvm.fetchProjects()
}
}
.background(Color(hexadecimal: "#F8F8F8"))
.ignoresSafeArea()
.navigationBarHidden(true)
}
}
}
I managed to solve the issue by changing the id variable to a String and re-did the fetch projects function. So in short I just completely scrapped the #DocumentID wrapper which didn't seem to work. The #FirestoreQuery query wrapper worked after I changed the ID variable in my data model, but I didn't need it again since my View Model did the job
Data Struct:
struct ProjectsData: Identifiable, Codable{
var id: String
var title: String?
var client: String?
var description: String?
var inspections: [InspectionsData]
enum CodingKeys: String, CodingKey{
case id
case title
case client
case description
case inspections
}
}
I refactored the function that gets documents from Firestore to this:
func fetchFireStoreData() {
db.collection("Projects").getDocuments { snapshot, error in
if error == nil {
if let snapshot = snapshot{
//Get all documents
self.projects = snapshot.documents.map({ document in
let id = document.documentID
let title = document["title"] as? String ?? ""
let client = document["client"] as? String ?? ""
let description = document["description"] as? String ?? ""
let inspections = document["inspections"] as? [String : [String : Any]]
var inspectionsArray = [InspectionsData]()
if let inspections = inspections {
for inspection in inspections {
let categoryText = inspection.value["category"] as? String ?? "error"
let category = Category(rawValue: categoryText) ?? .Electrical
let trade = inspection.value["trade"] as? String ?? "error"
let inspectionDate = (inspection.value["inspectionDate"] as? Timestamp)?.dateValue() ?? Date()
let dueDate = inspection.value["dueDate"] as? Date
let assigned = inspection.value["assigned"] as? Bool ?? false
let location = inspection.value["inspection"] as? String ?? ""
let images = inspection.value["images"] as? [String : [String : Any]]
let checklists = inspection.value["checklists"] as? [String : [String : Any]]
var imagesArray = [InspectionImages]()
var checklistsArray = [ChecklistsData]()
if let checklists = checklists{
for list in checklists {
let question = list.value["question"] as? String ?? "error"
let hasPassed = list.value["hasPassed"] as? Bool ?? false
let hasFailed = list.value["hasFailed"] as? Bool ?? false
let isnotApplicable = list.value["isnotApplicable"] as? Bool ?? false
checklistsArray.append(ChecklistsData(question: question, hasPassed: hasPassed, hasFailed: hasFailed, isnotApplicable: isnotApplicable))
}
}
inspectionsArray.append(InspectionsData(category: category, trade: trade, inspectionDate: inspectionDate , dueDate: dueDate ?? Date.now, assigned: assigned, location: location, images: imagesArray, checklists: checklistsArray))
if let images = images {
for image in images {
let url = image.value["url"] as? String ?? "error"
imagesArray.append(InspectionImages(url: url))
}
}
}
}
self.projects.append(ProjectsData(id: id ,title: title, client: client, description: description, inspections: inspectionsArray))
return ProjectsData(id: id, title: title, client: client, description: description, inspections: inspectionsArray )
})
}
}
}
}
I'm now able to get the correct Document ID and now I can use my updateChecklist function.

Swift Alamofire list view state

I'm trying to create a list view with some data I am pulling from an API. I'm struggling to understand how to take the data from the API response and putting it into the state for my app to use. Below is the content view in my application that is pulling the data.
import SwiftUI
import Alamofire
struct ContentView: View {
#State var results = [Bottle]()
var body: some View {
List(results, id: \.id) { item in
VStack(alignment: .leading) {
Text(item.name)
}
}.onAppear(perform: loadData)
}
func loadData() {
let request = AF.request("https://bevy-staging.herokuapp.com")
request.responseJSON { (data) in
print(data)
}
}
}
I've tried adding this to the result block
AF.request("https://bevy-staging.herokuapp.com/").responseJSON { response in
guard let data = response.data else { return }
if let response = try? JSONDecoder().decode([Bottle].self, from: data) {
DispatchQueue.main.async {
self.results = response
}
return
}
}
However nothing populates in my view and I get the following error.
nw_protocol_get_quic_image_block_invoke dlopen libquic failed
Why am I receiving this error and how can I get my data to display in the list vew?
Here is the model I am working with.
struct Bottle: Decodable {
var id: String
var name: String
var price: String
var sku: String
var size: String
var origination: String
var varietal: String
var brand_bottle: String
}
You need to add "?" to model data that can have null data, for all model rows which can obtain "null" need to use "?" or JSONDecoder wouldn't decode data to your model. Inside the model your rows "origination, varietal, brand_bottle" have "String" data type but from the server, you obtain "null", thus JSONDecoder can't recognize data.
You can check responses use services like "http://jsonviewer.stack.hu/" or any other.
Need to modify model data like below:
struct Bottle: Decodable {
var id: String
var name: String
var price: String
var sku: String
var size: String
var origination: String?
var varietal: String?
var brand_bottle: String?
}
I did recreate your project and all work well code below:
import SwiftUI
import Alamofire
struct ContentView: View {
#State var results = [Bottle]()
var body: some View {
List(results, id: \.id) { item in
VStack(alignment: .leading) {
Text(item.name)
}
}.onAppear(perform: loadData)
}
func loadData() {
AF.request("https://bevy-staging.herokuapp.com/").responseJSON { response in
guard let data = response.data else { return }
if let response = try? JSONDecoder().decode([Bottle].self, from: data) {
DispatchQueue.main.async {
self.results = response
}
return
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct Bottle: Decodable {
var id: String
var name: String
var price: String
var sku: String
var size: String
var origination: String?
var varietal: String?
var brand_bottle: String?
}

Resources