0

In SwiftUI, I call an API in a function. Then, I call that function somewhere else - the function allows me to temporarily save the API data to a local variable ONLY in that specific block of code.

What I need is a way to save the data outside of a block, because I'll use this variable a lot, and I need that data in order to specify different API calls later in the code. Everything I've researched indicates this is not possible.

Example API Call:

func fetchTeamData(String: String, completion: @escaping (TeamStructure)->())
{
    let userURL = "x" + String
    
    guard let url = URL(string: userURL) else { return }
    URLSession.shared.dataTask(with: url)
    {data, _, _ in

    self.teams = try! JSONDecoder().decode(TeamStructure.self, from: data!)
            
    DispatchQueue.main.async
    {
        completion(self.teams)
    }
    }.resume()
}

Example function call and my problem:

.onAppear()
{
    APICaller.fetchTeamData(String: "")
    {(teams) in
    self.requestedTeam = teams
        
    print(requestedTeam) //full dataset in this variable, I need this data
    }
    
    print(requestedTeam) //data is now gone
}

I've tried putting various functions/variables in an init block, but hit same issue where it becomes empty.

I've tried calling functions within the API Call method, but when I send the variable out, it's empty.

I've tried doing more complex data logic inside my view, nesting calls and loops, but I always hit a point where it goes "Hey, this is a view - the thing you're doing isn't allowed here".

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Matthew
  • 11
  • 1
  • If you want to use the data in a lot of places, you may want to consider loading and storing it inside an `EnvironmentObject` – jnpdx Jul 17 '23 at 18:59
  • I agree, but I think the issue is the data disappears from the variable outside of the method call area. I think the data would at least be available to the entire view where I declared the variable that is holding the data...but for some reason, the variable just goes empty. – Matthew Jul 17 '23 at 19:32
  • I think this is a misunderstanding of how async functions work. See https://stackoverflow.com/questions/25203556/returning-data-from-async-call-in-swift-function That would explain the issue you're seeing in the last code block. It's not "gone" it just isn't set yet – jnpdx Jul 17 '23 at 19:34
  • the "gone" print statement runs before the "working" print statement. Watch "Meet async/await" from WWDC – lorem ipsum Jul 17 '23 at 19:38
  • you have `print(requestedTeam) //data is now gone`, this is **not correct**. The data is not **available** at that place in the code because you are printing it **before** it is available. And this is because the function `fetchTeamData(...)` is asynchronous, look this up. Your `requestedTeam` is/should be declared as `@State var requestedTeam ...`, the view will `understand` it has changed and update the view all by itself. This is fundamantal to understanding and using SwiftUI. – workingdog support Ukraine Jul 17 '23 at 22:38
  • With regard to the async issues, the above comments are correct. Async/Await is much easier to reason than callback completions. My only addition is never force unwrap like this `self.teams = try! JSONDecoder().decode(TeamStructure.self, from: data!)`. This is a time bomb in your code and it will crash because something is nil at some point. Put the decoder in a `Do {} Catch {}` and remove the first `!`. For the data, either `guard let data` or `if let data` to safely unwrap it, depending upon your logic flow. – Yrb Jul 18 '23 at 12:37

0 Answers0