Swift change state and reload after API call with #binding - ios

I currently have a list of recipes that I fetch from a local API upon screen load. This page also has a search field on it that I want to hook up to pull certain data from this API. This API call stores the results in the state of the view. My goal is, when somebody searches, to pull those records and update the state, and reloading the view with new data.
I have seen different ways of doing this with #binding and #state, however, it seems from the examples I've been looking at the binding is in a different struct within another file. In my iteration, however, I just have some functions that pull data from this API. I'd like to avoid using reloadData() as I'd like to use #binding and #state wherever possible in my application.
struct RecipesView: View {
#State var recipes = [Recipe]()
#State var searchText = ""
var body: some View {
VStack {
HStack {
TextField("Search ...", text: $searchText)
.padding(7)
.padding(.horizontal, 25)
.background(Color(.systemGray6))
.cornerRadius(8)
.padding(.horizontal, 10)
}
VStack{
HStack {
Text("Categories")
.bold()
.multilineTextAlignment(.trailing)
.padding(10)
Spacer()
}
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 10) {
ForEach(SPIRITS, id:\.self){ spirit in
Button("\(spirit)", action: {
queryBySpirit(spirit: spirit)
})
.frame(width: 80, height: 40, alignment: .center)
.background(Color("Tope"))
.foregroundColor(Color("Onyx"))
.cornerRadius(15)
.font(.subheadline.bold())
}
}.padding([.leading, .trailing])
}
}
ScrollView {
VStack {
ForEach(recipes) { recipe in
NavigationLink(destination: RecipeView(recipe: recipe)) {
RecipeCard(recipe: recipe)
}
}.padding([.trailing])
}
}
}
.onAppear(perform: loadData)
.navigationBarTitle("Recipes")
.listStyle(InsetGroupedListStyle())
Color.gray.ignoresSafeArea()
}
func loadData() {
AF.request("http://localhost:3000/recipes").responseJSON { response in
guard let data = response.data else { return }
if let response = try? JSONDecoder().decode([Recipe].self, from: data) {
DispatchQueue.main.async {
self.recipes = response
}
return
}
}
}
func queryBySpirit(spirit: String) {
AF.request("http://localhost:3000/recipes?spirit=\(spirit)").responseJSON { response in
guard let data = response.data else { return }
if let response = try? JSONDecoder().decode([Recipe].self, from: data) {
DispatchQueue.main.async {
self.recipes = response
}
return
}
}
}
}
How can I use #binding within this file to take advantage of the hot reloading? Or, based on my iteration will I need to leverage reloadData() instead?
Spefically, I'd like to avoid using reloadData() as seen here: Swift CollectionView reload data after API call
I'd love to be able to leverage Changing #State variable does not update the View in SwiftUI
However I'm unsure of how to do that with what I have currently.

Related

Refreshable Indicator is presented on view's appear

Once a view appears refreshable indicator is already visible without the necessity of performing the swipe on list. When I swipe the list up it hides and then pull to refresh can be performed in correct way (it shows, performs actions and hide).
My View:
struct OrdersView: View {
#EnvironmentObject private var tabBarStateManager: TabBarStateManager
#EnvironmentObject private var profileViewModel: ProfileViewModel
#StateObject private var ordersViewModel: OrdersViewModel = OrdersViewModel()
#Environment(\.dismiss) private var dismiss: DismissAction
var body: some View {
List {
ForEach(ordersViewModel.datesForOrdersViewListSections, id: \.self) { stringDate in
Section {
ForEach(ordersViewModel.getOrdersFor(date: stringDate), id: \.self) { order in
NavigationLink(destination: OrderDetailsView(order: order,
orderProductsList: ordersViewModel.getOrderProductsFor(order: order))
.environmentObject(ordersViewModel)) {
VStack(alignment: .leading, spacing: 20) {
HStack(spacing: 10) {
Text(order.id)
.font(.ssCallout)
Spacer()
Text(Date.getDayAndMonthFrom(date: order.orderDate))
.font(.ssTitle3)
.foregroundColor(.accentColor)
}
Text("$\(order.totalCost, specifier: "%.2f")")
.font(.ssTitle3)
.foregroundColor(.accentColor)
VStack(alignment: .leading) {
HStack {
Text(TexterifyManager.localisedString(key: .ordersView(.products)))
.font(.ssCallout)
Text("\(ordersViewModel.getOrderProductsFor(order: order).count)")
.font(.ssTitle3)
.foregroundColor(.accentColor)
}
HStack {
Text(TexterifyManager.localisedString(key: .ordersView(.orderStatus)))
.font(.ssCallout)
Text(order.status.rawValue)
.font(.ssTitle3)
.foregroundColor(.accentColor)
}
}
}
.padding(.vertical)
}
}
} header: {
Text(stringDate)
.font(.ssTitle1)
.foregroundColor(.accentColor)
}
}
}
.listStyle(.grouped)
.refreshable {
profileViewModel.fetchUserOrders {
ordersViewModel.userOrders = profileViewModel.userOrders
}
}
.navigationTitle(TexterifyManager.localisedString(key: .ordersView(.navigationTitle)))
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
dismiss()
} label: {
Image(systemName: "arrow.backward.circle.fill")
.resizable()
.frame(width: 30, height: 30)
.foregroundColor(.accentColor)
}
}
}
.onAppear {
ordersViewModel.userOrders = profileViewModel.userOrders
}
}
}
Changing .refreshable modifier order does not fix the problem
Changing .listStyle also does not help
The problem only occurs on physical device on iPhone 13 Pro Max (iOS 16.1). The same version of simulator does not have the problem.
EDIT:
I discovered that my problem only occurs when .navigationBarTitleDisplayMode is set to .inline instead of default .large
Screenshot:
Here is an example implementation, not exactly yours because you have complex structures that I was not able to reproduce. I hope you get some good from this example:
//
// ContentView.swift
// Refreshable
//
// Created by Allan Garcia on 11/11/22.
//
import SwiftUI
struct ContentView: View {
#State private var isLoading = true
// You may start the view starting with a loading state, before the data was loaded
#State private var myList = [String]() {
didSet {
isLoading = false
}
}
// Once the data is set isLoading (the loading state) is turned off
var body: some View {
NavigationView {
List {
if isLoading {
ProgressView()
.progressViewStyle(.circular)
.font(.largeTitle)
}
ForEach(myList, id: \.self) { item in
Text(item)
}
}
.listStyle(.plain)
.onAppear {
DispatchQueue.main.async {
isLoading = true
withAnimation {
self.myList = ContentView.fetchedList[0..<10].map { $0.uppercased() }
}
}
// On Appear you will probably fetch "some" data with pagination
}
.refreshable {
DispatchQueue.main.async {
withAnimation {
self.myList = ContentView.fetchedList.map { $0.uppercased() }
// A note here... refreshable is good when new data comes on top. If the data comes from bellow is
// a infinite scrolling approach much more advisable.
}
}
// .refreshable works fine here... ir will fetch more data... here it fetchs all, but is probably a
// good practice to fetch "some" more, and let the user read through until he wants to fetch more and
// trigger refreshable again.
}
}
.padding()
}
static let fetchedList = ["a","abandon","ability","able","abortion","about","above","abroad","absence","absolute","absolutely","absorb","abuse","academic","accept","access","accident","accompany","accomplish","according","account","accurate","accuse","achieve","achievement","acid","acknowledge","acquire","across","act","action","active","activist","activity","actor","actress","actual","actually","ad","adapt","add","addition","additional","address","adequate","adjust","adjustment","administration","administrator","admire","admission","admit","adolescent","adopt","adult","advance","advanced","advantage","adventure","advertising","advice","advise","adviser","advocate","affair","affect","afford","afraid","African","African-American","after","afternoon","again","against","age","agency","agenda","agent","aggressive","ago","agree","agreement","agricultural","ah","ahead","aid","aide","AIDS","aim","air","aircraft","airline","airport","album","alcohol","alive","all","alliance","allow","ally","almost","alone","along","already","also","alter","alternative","although","always","AM","amazing","American","among","amount","analysis","analyst","analyze","ancient","and","anger","angle","angry","animal","anniversary","announce","annual","another","answer","anticipate","anxiety","any","anybody","anymore","anyone","anything","anyway","anywhere","apart","apartment","apparent","apparently","appeal","appear","appearance","apple","application","apply","appoint","appointment","appreciate","approach","appropriate","approval","approve","approximately","Arab","architect","area","argue","argument","arise","arm","armed","army","around","arrange","arrangement","arrest","arrival","arrive","art","article","artist","artistic","as","Asian","aside","ask","asleep","aspect","assault","assert","assess","assessment","asset","assign","assignment","assist","assistance","assistant","associate","association","assume","assumption","assure","at","athlete","athletic","atmosphere","attach","attack","attempt","attend","attention","attitude","attorney","attract","attractive","attribute","audience","author","authority","auto","available","average","avoid","award","aware","awareness","away","awful","baby","back","background","bad","badly","bag","bake","balance","ball","ban","band","bank","bar","barely","barrel","barrier","base","baseball","basic","basically","basis","basket","basketball","bathroom","battery","battle","be","beach","bean","bear","beat","beautiful","beauty","because","become","bed","bedroom","beer","before","begin","beginning","behavior","behind","being","belief","believe","bell","belong","below","belt","bench","bend","beneath","benefit","beside","besides","best","bet","better","between","beyond","Bible","big","bike","bill","billion","bind","biological","bird","birth","birthday","bit","bite","black","blade","blame","blanket","blind","block","blood","blow","blue","board","boat","body","bomb","bombing","bond","bone","book","boom","boot","border","born","borrow","boss","both","bother","bottle","bottom","boundary","bowl","box","boy","boyfriend","brain","branch","brand","bread","break","breakfast","breast","breath","breathe","brick","bridge","brief","briefly","bright","brilliant","bring","British","broad","broken","brother","brown","brush","buck","budget","build","building","bullet","bunch","burden","burn","bury","bus","business","busy","but","butter","button","buy","buyer","by","cabin","cabinet","cable","cake","calculate","call","camera","camp","campaign","campus","can","Canadian","cancer","candidate","cap","capability","capable","capacity","capital","captain","capture","car","carbon","card","care","career","careful","carefully","carrier","carry","case","cash","cast","cat","catch","category","Catholic","cause","ceiling","celebrate","celebration","celebrity","cell","center","central","century","CEO","ceremony","certain","certainly","chain","chair","chairman","challenge","chamber","champion","championship","chance","change","changing","channel","chapter","character","characteristic","characterize","charge","charity","chart","chase","cheap","check","cheek","cheese","chef","chemical","chest","chicken","chief","child","childhood","Chinese","chip","chocolate","choice","cholesterol","choose","Christian","Christmas","church","cigarette","circle","circumstance","cite","citizen","city","civil","civilian","claim","class","classic","classroom","clean","clear","clearly","client","climate","climb","clinic","clinical","clock","close","closely","closer","clothes","clothing","cloud","club","clue","cluster","coach","coal","coalition","coast","coat","code","coffee","cognitive","cold","collapse","colleague","collect","collection","collective","college","colonial","color","column","combination","combine","come","comedy","comfort","comfortable","command","commander","comment","commercial","commission","commit","commitment","committee","common","communicate","communication","community","company","compare","comparison","compete","competition","competitive","competitor","complain","complaint","complete","completely","complex","complicated","component","compose","composition","comprehensive","computer","concentrate","concentration","concept","concern","concerned","concert","conclude","conclusion","concrete","condition","conduct","conference","confidence","confident","confirm","conflict","confront","confusion","Congress","congressional","connect","connection","consciousness","consensus","consequence","conservative","consider","considerable","consideration","consist","consistent","constant","constantly","constitute","constitutional","construct","construction","consultant","consume","consumer","consumption","contact","contain","container","contemporary","content","contest","context","continue","continued","contract","contrast","contribute","contribution","control","controversial","controversy","convention","conventional","conversation","convert","conviction","convince","cook","cookie","cooking","cool","cooperation","cop","cope","copy","core","corn","corner","corporate","corporation","correct","correspondent","cost","cotton","couch","could","council","counselor","count","counter","country","county","couple","courage","course","court","cousin","cover","coverage","cow","crack","craft","crash","crazy","cream","create","creation","creative","creature","credit","crew","crime","criminal","crisis","criteria","critic","critical","criticism","criticize","crop","cross","crowd","crucial","cry","cultural","culture","cup","curious","current","currently","curriculum","custom","customer","cut","cycle","dad","daily","damage","dance","danger","dangerous","dare","dark","darkness","data","date","daughter","day","dead","deal","dealer","dear","death","debate","debt","decade","decide","decision","deck","declare","decline","decrease","deep","deeply","deer","defeat","defend","defendant","defense","defensive","deficit","define","definitely","definition","degree","delay","deliver","delivery","demand","democracy","Democrat","democratic","demonstrate","demonstration","deny","department","depend","dependent","depending","depict","depression","depth","deputy","derive","describe","description","desert","deserve","design","designer","desire","desk","desperate","despite","destroy","destruction","detail","detailed","detect","determine","develop","developing","development","device","devote","dialogue","die","diet","differ","difference","different","differently","difficult","difficulty","dig","digital","dimension","dining","dinner","direct","direction","directly","director","dirt","dirty","disability","disagree","disappear","disaster","discipline","discourse","discover","discovery","discrimination","discuss","discussion","disease","dish","dismiss","disorder","display","dispute","distance","distant","distinct","distinction","distinguish","distribute","distribution","district","diverse","diversity","divide","division","divorce","DNA","do","doctor","document","dog","domestic","dominant","dominate","door","double","doubt","down","downtown","dozen","draft","drag","drama","dramatic","dramatically","draw","drawing","dream","dress","drink","drive","driver","drop","drug","dry","due","during","dust","duty","each","eager","ear","early","earn","earnings","earth","ease","easily","east","eastern","easy","eat","economic","economics","economist","economy","edge","edition","editor","educate","education","educational","educator","effect","effective","effectively","efficiency","efficient","effort","egg","eight","either","elderly","elect","election","electric","electricity","electronic","element","elementary","eliminate","elite","else","elsewhere","e-mail","embrace","emerge","emergency","emission","emotion","emotional","emphasis","emphasize","employ","employee","employer","employment","empty","enable","encounter","encourage","end","enemy","energy","enforcement","engage","engine","engineer","engineering","English","enhance","enjoy","enormous","enough","ensure","enter","enterprise","entertainment","entire","entirely","entrance","entry","environment","environmental","episode","equal","equally","equipment","era","error","escape","especially","essay","essential","essentially","establish","establishment","estate","estimate","etc","ethics","ethnic","European","evaluate","evaluation","even","evening","event","eventually","ever","every","everybody","everyday","everyone","everything","everywhere","evidence","evolution","evolve","exact","exactly","examination","examine","example","exceed","excellent","except","exception","exchange","exciting","executive","exercise","exhibit","exhibition","exist","existence","existing","expand","expansion","expect","expectation","expense","expensive","experience","experiment","expert","explain","explanation","explode","explore","explosion","expose","exposure","express","expression","extend","extension","extensive","extent","external","extra","extraordinary","extreme","extremely","eye","fabric","face","facility","fact","factor","factory","faculty","fade","fail","failure","fair","fairly","faith","fall","false","familiar","family","famous","fan","fantasy","far","farm","farmer","fashion","fast","fat","fate","father","fault","favor","favorite","fear","feature","federal","fee","feed","feel","feeling","fellow","female","fence","few","fewer","fiber","fiction","field","fifteen","fifth","fifty","fight","fighter","fighting","figure","file","fill","film","final","finally","finance","financial","find","finding","fine","finger","finish","fire","firm","first","fish","fishing","fit","fitness","five","fix","flag","flame","flat","flavor","flee","flesh","flight","float","floor","flow","flower","fly","focus","folk","follow","following","food","foot","football","for","force","foreign","forest","forever","forget","form","formal","formation","former","formula","forth","fortune","forward","found","foundation","founder","four","fourth","frame","framework","free","freedom","freeze","French","frequency","frequent","frequently","fresh","friend","friendly","friendship","from","front","fruit","frustration","fuel","full","fully","fun","function","fund","fundamental","funding","funeral","funny","furniture","furthermore","future","gain","galaxy","gallery","game","gang","gap","garage","garden","garlic","gas","gate","gather","gay","gaze","gear","gender","gene","general","generally","generate","generation","genetic","gentleman","gently","German","gesture","get","ghost","giant","gift","gifted","girl","girlfriend","give","given","glad","glance","glass","global","glove","go","goal","God","gold","golden","golf","good","government","governor","grab","grade","gradually","graduate","grain","grand","grandfather","grandmother","grant","grass","grave","gray","great","greatest","green","grocery","ground","group","grow","growing","growth","guarantee","guard","guess","guest","guide","guideline","guilty","gun","guy","habit","habitat","hair","half","hall","hand","handful","handle","hang","happen","happy","hard","hardly","hat","hate","have","he","head","headline","headquarters","health","healthy","hear","hearing","heart","heat","heaven","heavily","heavy","heel","height","helicopter","hell","hello","help","helpful","her","here","heritage","hero","herself","hey","hi","hide","high","highlight","highly","highway","hill","him","himself","hip","hire","his","historian","historic","historical","history","hit","hold","hole","holiday","holy","home","homeless","honest","honey","honor","hope","horizon","horror","horse","hospital","host","hot","hotel","hour","house","household","housing","how","however","huge","human","humor","hundred","hungry","hunter","hunting","hurt","husband","hypothesis","I","ice","idea","ideal","identification","identify","identity","ie","if","ignore","ill","illegal","illness","illustrate","image","imagination","imagine","immediate","immediately","immigrant","immigration","impact","implement","implication","imply","importance","important","impose","impossible","impress","impression","impressive","improve","improvement","in","incentive","incident","include","including","income","incorporate","increase","increased","increasing","increasingly","incredible","indeed","independence","independent","index","Indian","indicate","indication","individual","industrial","industry","infant","infection","inflation","influence","inform","information","ingredient","initial","initially","initiative","injury","inner","innocent","inquiry","inside","insight","insist","inspire","install","instance","instead","institution","institutional","instruction","instructor","instrument","insurance","intellectual","intelligence","intend","intense","intensity","intention","interaction","interest","interested","interesting","internal","international","Internet","interpret","interpretation","intervention","interview","into","introduce","introduction","invasion","invest","investigate","investigation","investigator","investment","investor","invite","involve","involved","involvement","Iraqi","Irish","iron","Islamic","island","Israeli","issue","it","Italian","item","its","itself","jacket","jail","Japanese","jet","Jew","Jewish","job","join","joint","joke","journal","journalist","journey","joy","judge","judgment","juice","jump","junior","jury","just","justice","justify","keep","key","kick","kid","kill","killer","killing","kind","king","kiss","kitchen","knee","knife","knock","know","knowledge","lab","label","labor","laboratory","lack","lady","lake","land","landscape","language","lap","large","largely","last","late","later","Latin","latter","laugh","launch","law","lawn","lawsuit","lawyer","lay","layer","lead","leader","leadership","leading","leaf","league","lean","learn","learning","least","leather","leave","left","leg","legacy","legal","legend","legislation","legitimate","lemon","length","less","lesson","let","letter","level","liberal","library","license","lie","life","lifestyle","lifetime","lift","light","like","likely","limit","limitation","limited","line","link","lip","list","listen","literally","literary","literature","little","live","living","load","loan","local","locate","location","lock","long","long-term","look","loose","lose","loss","lost","lot","lots","loud","love","lovely","lover","low","lower","luck","lucky","lunch","lung","machine","mad","magazine","mail","main","mainly","maintain","maintenance","major","majority","make","maker","makeup","male","mall","man","manage","management","manager","manner","manufacturer","manufacturing","many","map","margin","mark","market","marketing","marriage","married","marry","mask","mass","massive","master","match","material","math","matter","may","maybe","mayor","me","meal","mean","meaning","meanwhile","measure","measurement","meat","mechanism","media","medical","medication","medicine","medium","meet","meeting","member","membership","memory","mental","mention","menu","mere","merely","mess","message","metal","meter","method","Mexican","middle","might","military","milk","million","mind","mine","minister","minor","minority","minute","miracle","mirror","miss","missile","mission","mistake","mix","mixture","mm-hmm","mode","model","moderate","modern","modest","mom","moment","money","monitor","month","mood","moon","moral","more","moreover","morning","mortgage","most","mostly","mother","motion","motivation","motor","mount","mountain","mouse","mouth","move","movement","movie","Mr","Mrs","Ms","much","multiple","murder","muscle","museum","music","musical","musician","Muslim","must","mutual","my","myself","mystery","myth","naked","name","narrative","narrow","nation","national","native","natural","naturally","nature","near","nearby","nearly","necessarily","necessary","neck","need","negative","negotiate","negotiation","neighbor","neighborhood","neither","nerve","nervous","net","network","never","nevertheless","new","newly","news","newspaper","next","nice","night","nine","no","nobody","nod","noise","nomination","none","nonetheless","nor","normal","normally","north","northern","nose","not","note","nothing","notice","notion","novel","now","nowhere","n't","nuclear","number","numerous","nurse","nut","object","objective","obligation","observation","observe","observer","obtain","obvious","obviously","occasion","occasionally","occupation","occupy","occur","ocean","odd","odds","of","off","offense","offensive","offer","office","officer","official","often","oh","oil","ok","okay","old","Olympic","on","once","one","ongoing","onion","online","only","onto","open","opening","operate","operating","operation","operator","opinion","opponent","opportunity","oppose","opposite","opposition","option","or","orange","order","ordinary","organic","organization","organize","orientation","origin","original","originally","other","others","otherwise","ought","our","ourselves","out","outcome","outside","oven","over","overall","overcome","overlook","owe","own","owner","pace","pack","package","page","pain","painful","paint","painter","painting","pair","pale","Palestinian","palm","pan","panel","pant","paper","parent","park","parking","part","participant","participate","participation","particular","particularly","partly","partner","partnership","party","pass","passage","passenger","passion","past","patch","path","patient","pattern","pause","pay","payment","PC","peace","peak","peer","penalty","people","pepper","per","perceive","percentage","perception","perfect","perfectly","perform","performance","perhaps","period","permanent","permission","permit","person","personal","personality","personally","personnel","perspective","persuade","pet","phase","phenomenon","philosophy","phone","photo","photograph","photographer","phrase","physical","physically","physician","piano","pick","picture","pie","piece","pile","pilot","pine","pink","pipe","pitch","place","plan","plane","planet","planning","plant","plastic","plate","platform","play","player","please","pleasure","plenty","plot","plus","PM","pocket","poem","poet","poetry","point","pole","police","policy","political","politically","politician","politics","poll","pollution","pool","poor","pop","popular","population","porch","port","portion","portrait","portray","pose","position","positive","possess","possibility","possible","possibly","post","pot","potato","potential","potentially","pound","pour","poverty","powder","power","powerful","practical","practice","pray","prayer","precisely","predict","prefer","preference","pregnancy","pregnant","preparation","prepare","prescription","presence","present","presentation","preserve","president","presidential","press","pressure","pretend","pretty","prevent","previous","previously","price","pride","priest","primarily","primary","prime","principal","principle","print","prior","priority","prison","prisoner","privacy","private","probably","problem","procedure","proceed","process","produce","producer","product","production","profession","professional","professor","profile","profit","program","progress","project","prominent","promise","promote","prompt","proof","proper","properly","property","proportion","proposal","propose","proposed","prosecutor","prospect","protect","protection","protein","protest","proud","prove","provide","provider","province","provision","psychological","psychologist","psychology","public","publication","publicly","publish","publisher","pull","punishment","purchase","pure","purpose","pursue","push","put","qualify","quality","quarter","quarterback","question","quick","quickly","quiet","quietly","quit","quite","quote","race","racial","radical","radio","rail","rain","raise","range","rank","rapid","rapidly","rare","rarely","rate","rather","rating","ratio","raw","reach","react","reaction","read","reader","reading","ready","real","reality","realize","really","reason","reasonable","recall","receive","recent","recently","recipe","recognition","recognize","recommend","recommendation","record","recording","recover","recovery","recruit","red","reduce","reduction","refer","reference","reflect","reflection","reform","refugee","refuse","regard","regarding","regardless","regime","region","regional","register","regular","regularly","regulate","regulation","reinforce","reject","relate","relation","relationship","relative","relatively","relax","release","relevant","relief","religion","religious","rely","remain","remaining","remarkable","remember","remind","remote","remove","repeat","repeatedly","replace","reply","report","reporter","represent","representation","representative","Republican","reputation","request","require","requirement","research","researcher","resemble","reservation","resident","resist","resistance","resolution","resolve","resort","resource","respect","respond","respondent","response","responsibility","responsible","rest","restaurant","restore","restriction","result","retain","retire","retirement","return","reveal","revenue","review","revolution","rhythm","rice","rich","rid","ride","rifle","right","ring","rise","risk","river","road","rock","role","roll","romantic","roof","room","root","rope","rose","rough","roughly","round","route","routine","row","rub","rule","run","running","rural","rush","Russian","sacred","sad","safe","safety","sake","salad","salary","sale","sales","salt","same","sample","sanction","sand","satellite","satisfaction","satisfy","sauce","save","saving","say","scale","scandal","scared","scenario","scene","schedule","scheme","scholar","scholarship","school","science","scientific","scientist","scope","score","scream","screen","script","sea","search","season","seat","second","secret","secretary","section","sector","secure","security","see","seed","seek","seem","segment","seize","select","selection","self","sell","Senate","senator","send","senior","sense","sensitive","sentence","separate","sequence","series","serious","seriously","serve","service","session","set","setting","settle","settlement","seven","several","severe","sex","sexual","shade","shadow","shake","shall","shape","share","sharp","she","sheet","shelf","shell","shelter","shift","shine","ship","shirt","shit","shock","shoe","shoot","shooting","shop","shopping","shore","short","shortly","shot","should","shoulder","shout","show","shower","shrug","shut","sick","side","sigh","sight","sign","signal","significance","significant","significantly","silence","silent","silver","similar","similarly","simple","simply","sin","since","sing","singer","single","sink","sir","sister","sit","site","situation","six","size","ski","skill","skin","sky","slave","sleep","slice","slide","slight","slightly","slip","slow","slowly","small","smart","smell","smile","smoke","smooth","snap","snow","so","so-called","soccer","social","society","soft","software","soil","solar","soldier","solid","solution","solve","some","somebody","somehow","someone","something","sometimes","somewhat","somewhere","son","song","soon","sophisticated","sorry","sort","soul","sound","soup","source","south","southern","Soviet","space","Spanish","speak","speaker","special","specialist","species","specific","specifically","speech","speed","spend","spending","spin","spirit","spiritual","split","spokesman","sport","spot","spread","spring","square","squeeze","stability","stable","staff","stage","stair","stake","stand","standard","standing","star","stare","start","state","statement","station","statistics","status","stay","steady","steal","steel","step","stick","still","stir","stock","stomach","stone","stop","storage","store","storm","story","straight","strange","stranger","strategic","strategy","stream","street","strength","strengthen","stress","stretch","strike","string","strip","stroke","strong","strongly","structure","struggle","student","studio","study","stuff","stupid","style","subject","submit","subsequent","substance","substantial","succeed","success","successful","successfully","such","sudden","suddenly","sue","suffer","sufficient","sugar","suggest","suggestion","suicide","suit","summer","summit","sun","super","supply","support","supporter","suppose","supposed","Supreme","sure","surely","surface","surgery","surprise","surprised","surprising","surprisingly","surround","survey","survival","survive","survivor","suspect","sustain","swear","sweep","sweet","swim","swing","switch","symbol","symptom","system","table","tablespoon","tactic","tail","take","tale","talent","talk","tall","tank","tap","tape","target","task","taste","tax","taxpayer","tea","teach","teacher","teaching","team","tear","teaspoon","technical","technique","technology","teen","teenager","telephone","telescope","television","tell","temperature","temporary","ten","tend","tendency","tennis","tension","tent","term","terms","terrible","territory","terror","terrorism","terrorist","test","testify","testimony","testing","text","than","thank","thanks","that","the","theater","their","them","theme","themselves","then","theory","therapy","there","therefore","these","they","thick","thin","thing","think","thinking","third","thirty","this","those","though","thought","thousand","threat","threaten","three","throat","through","throughout","throw","thus","ticket","tie","tight","time","tiny","tip","tire","tired","tissue","title","to","tobacco","today","toe","together","tomato","tomorrow","tone","tongue","tonight","too","tool","tooth","top","topic"]
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Delay SwiftUI view rendering until Published object finishes loading [duplicate]

This question already has answers here:
Displaying activity indicator while loading async request in SwiftUI
(2 answers)
Closed 8 months ago.
I am trying to build an app using SwiftUI, and I've created a class responsible for performing an API request and decoding the response into a weatherResponse object, and have annotated this object as #Published within this class.
In my view, I have instantiated this class using the #StateObject annotation. According to this post, this should be the correct way of observing the weatherResponse object within my view so that it automatically updates.
However, when my view loads the instance of WeatherNetworking hasn't even been initialized, and so the first reference to the object published within that class results in a nil value access.
struct MainWeatherView: View {
#StateObject var weatherNetworking = WeatherNetworking()
var body: some View {
VStack {
Image(systemName: weatherNetworking.getConditionName(weatherID: (weatherNetworking.weatherResponse!.current.weather[0].id))) // weatherResponse is nil
.resizable()
.aspectRatio( contentMode: .fit)
.scaleEffect(0.75)
.padding()
HStack {
VStack{
Text("Temperature")
.fontWeight(.bold)
.font(.system(size: 24))
Text("Humidity")
.fontWeight(.bold)
.font(.system(size: 24))
...
}
VStack {
Text("\(weatherNetworking.weatherResponse!.current.temp, specifier: "%.2f") °F")
.fontWeight(.bold)
.font(.system(size: 24))
Text("\(weatherNetworking.weatherResponse!.current.humidity, specifier: "%.0f") %")
.fontWeight(.bold)
.font(.system(size: 24))
...
}
}
}
.onAppear {
self.weatherNetworking.getMainWeather()
}
}
}
class WeatherNetworking: ObservableObject {
#StateObject var locationManager = LocationManager()
#Published var weatherResponse: WeatherResponse?
func getMainWeather() {
print("Location:", locationManager.lastLocation?.coordinate.latitude, locationManager.lastLocation?.coordinate.longitude)
if let loc = URL(string: "https://api.openweathermap.org/data/2.5/onecall?appid=redacted&exclude=minutely&units=imperial&lat=\(locationManager.lastLocation?.coordinate.latitude ?? 0)&lon=\(locationManager.lastLocation?.coordinate.longitude ?? 0)") {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: loc) { data, response, error in
if error == nil {
let decoder = JSONDecoder()
if let safeData = data {
do {
let results = try decoder.decode(WeatherResponse.self, from: safeData)
DispatchQueue.main.async {
self.weatherResponse = results
}
print("weatherResponse was succesfully updated")
} catch {
print(error)
}
}
} else {
print(error!)
}
}
task.resume()
}
}
}
None of the print statements within getMainWeather() execute which leads me to believe that the view is attempting to assign values before the function is called. How can I delay the assignment of these values within my view until after the onAppear() method finishes? it is worth noting that just as MainWeatherView depends upon the instantiation and asynchronous calls in WeatherNetworking, so too WeatherNetworking depends upon an instance of LocationManager.
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
#Published var locationStatus: CLAuthorizationStatus?
#Published var lastLocation: CLLocation?
...
}
Make dependent views conditional, like
VStack {
if let response = weatherNetworking.weatherResponse {
Image(systemName: weatherNetworking.getConditionName(weatherID: (response.current.weather[0].id))) // weatherResponse is nil
.resizable()
.aspectRatio( contentMode: .fit)
.scaleEffect(0.75)
.padding()
}
// .. other code

I can't transfer data to each index

I am trying to transfer the same API data from the first view and display the rest of the details in the second view
The problem is that the same first data is displayed in all index
struct model: Codable, Identifiable {
let id = UUID()
var details : String
var title : String
}
and fetch data here
class Api : ObservableObject{
#Published var models : [model] = []
func getData (url : String) {
guard let url = URL(string: url) else { return }
var request = URLRequest(url: url)
request.setValue("Bearer \(APIgetURL.Token)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, responce, err in
guard let data = data else { return }
do {
let dataModel = try JSONDecoder().decode([model].self, from: data)
DispatchQueue.main.async {
self.models = dataModel
}
} catch {
print("error: ", error)
}
}
.resume()
}
}
Here I present the data in the first view
ForEach(modelname.models) { item in
NavigationLink(destination: DetilesTap1(modelname: modelname)) {
Rectangle()
.cornerRadius(15)
.frame(width: .infinity, height: 40)
.foregroundColor(.white)
.shadow(color: .black.opacity(0.3), radius: 20)
.padding(.trailing).padding(.leading)
.overlay(
HStack {
Text(item.title)
.padding(.trailing,30).padding(.leading,30)
Spacer()
Image(systemName: "arrow.down.doc.fill")
.padding(.trailing,30).padding(.leading,30)
}
)
}
}
Here is the second view
ForEach(modelname.models) { item in
VStack(alignment: .center) {
VStack(spacing: 10) {
Text(item.title)
Text(item.details)
Spacer()
}
}
}
I tried to put the id and the same problem
Despite all the explanations and methods available, they all have the same problem
You haven't posted a Minimal Reproducible Example (MRE), so this is an educated guess. Assuming that
#StateObject var modelname = Api()
Then your first view should be:
// keep you naming consistent. item is really of type Model, so call it model.
ForEach(modelname.models) { model in
// Pass just the model data you want to display, not everything.
NavigationLink(destination: DetilesTap1(model: model)) {
...
}
in your second view:
struct DetailView: View {
let model: Model
var body: some View {
// the two VStack were redundant.
VStack(alignment: .center, spacing: 10) {
Text(model.title)
Text(model.details)
Spacer()
}
}
}
You just need to pass the data you want to display, not everything all over again. That is the point of the ForEach. It allows you to take each element and deal with it individually no indexes needed. Please study Apple’s SwiftUI Tutorials & Stanford’s CS193P. You need a better base of knowledge on how SwiftUI works.

How To Get Detail Api In Swift UI with Alamofire And Combine?

My Network Manager With Alamofire is Like this for get all API (NetworkManager.swift)
#Published var games = GamesDataList(results: [])
#Published var loading = false
private let api_url_base = "https://api.rawg.io/api/games"
And I want to go to navigation when I retrieve data based on ID LIst sent: (HomeView.swift)
List(networkManager.games.results) { game in
NavigationLink(destination: GameDetailView(game: game)){
GamesRowView(game: game)
}
}
And if I want to switch pages, NetworkDetail.swift has to be like that so that the Alamofire takes away from the ID details dynamic.
private func loadDetailData() {
let parameters = "12"
AF.request("\(api_url_detail)/\(id)",)
.responseJSON{ response in
guard let data = response.data else { return }
let gamesDetail = try! JSONDecoder().decode(GamesDetail.self, from: data)
print(gamesDetail)
DispatchQueue.main.async {
self.gamesDetail = gamesDetail
self.loading = false
}
}
And this my GameDetailView.swift
var game: Games
#ObservedObject var networkDetail = NetworkDetail()
var body: some View {
VStack {
URLImage(URL(string: "\(networkDetail.gamesDetail.background_image)")!, delay: 0.25) {proxy in
proxy.image.resizable()
.frame(width: 120, height: 80)
.aspectRatio(contentMode: .fill)
.clipped()
}
HStack {
Text("Description").foregroundColor(.gray)
Spacer()
}
Text(networkDetail.gamesDetail.description).lineLimit(nil)
Spacer()
}.navigationBarTitle(Text(game.slug), displayMode: .inline)
.padding()
}
I want when to click Item in List it will passing ID and make Request from Alamofire:
Please help me thanks. Right now the detailed API is still static.

How we get the data and show like viewdidload using swiftUI

i'm trying to work with swiftUI but i'm having an issue. i want to fetch the data from firebase and show that data to the list. i used mutating function to modify the variable. now when i called that function than it give me error. how i can solve this please help me. below are the code i'm using.
struct UserListView : View {
var body: some View{
VStack{
List{
VStack(alignment:.leading){
HStack{
Text("Favroute").frame(alignment: .leading).padding(.leading, 20)
Spacer()
Text("All").frame(alignment: .trailing)
}
ScrollView(.horizontal, content: {
HStack(spacing: 10) {
ForEach(0..<10) { index in
StatusView(statusImage: "nature")
}
}
.padding(.leading, 10)
})
.frame(height: 190)
}
ForEach(0..<10){_ in
HStack{
Group{
NavigationLink(destination: ChatView()){
UserImageView(imageName: "profileDummy").padding(.leading, 5)
Text("User Name").padding(.leading,10)
}
}
}.frame( height: 40)
}.environment(\.defaultMinListRowHeight, 40)
}
}
.navigationBarTitle("UserList",displayMode: .inline)
.onAppear {
self.userList()
}
}
var userDataList = [UserModel]()
mutating func userList() {
databaseReference.child(DatabaseNode.Users.root.rawValue).observe(.value) { (snapShot) in
if snapShot.exists(){
if let friendsDictionary = snapShot.value{
for each in friendsDictionary as! [String : AnyObject]{
print(each)
if let user = each.value as? [String : Any]{
let data = UserModel(userId: JSON(user["userId"] ?? "").stringValue, name: JSON(user["name"] ?? "").stringValue)
print(data)
self.userDataList.append(data)
}
}
}
}
}
}
}
below are the error message i'm getting:
Cannot use mutating member on immutable value: 'self' is immutable
You should declare your userDataList property like so #State var userDataList = [UserModel](). This way this property will be stored by SwiftUI outside of your struct and can be mutated.

Resources