TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

Call a JSON with a general func

Forums > iOS

Swift, storyboards

I can acces to information in a JSON in a url. It works well.

My question is: can I have the func outside any class? In the example I provide, If I put func getData outside the class ViewController, is there a way I can call let result2 when I click the button check?

struct User: Codable {
    let name: String
    let email: String
}

func getData() {
    let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
    URLSession.shared.dataTask(with: url) { data, _, _ in
        if let data = data {
            let result = try? JSONDecoder().decode([User].self, from: data)
            let result2 = result![0].name
            //print (result2)
        }
    }.resume()
}

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    @IBAction func check(_ sender: NSButton) {
        getData()
        //How can I call result2 here?
    }

}

3      

You would need to return a value from your getData function.

3      

I do not know how to do it. I tried many things. For instance:

func getData() -> (result2:String, result3:String) {
    let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
    URLSession.shared.dataTask(with: url) { data, _, _ in
        if let data = data {
            let result = try? JSONDecoder().decode([User].self, from: data)
            let result2 = result![0].name
            let result3 = result![0].email
            //print (result2)
            return (result2, result3) // Error: Unexpected non-vioid return value in void function
        }
    }.resume()
}

3      

The usual way to return a value from an asynchronous action (such as using URLSession to query a URL) is to provide a completion handler. Something like this:

func getData(completion: (User?) -> Void) {
    let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
    URLSession.shared.dataTask(with: url) { data, _, _ in
        if let data = data {
            do {
                let result = try JSONDecoder().decode([User].self, from: data)
                completion(result[0])
            } catch {
                completion(nil)
            }
        }
    }.resume()
}

And you would call it like this:

@IBAction func check(_ sender: NSButton) {
    getData { user in
       //user is a User?, so either a valid User or nil
       //do whatever you want with it
    }
}

Even better would be to supply a Result type to the completion handler:

enum MyErrorType: Error {
    case invalidUser
    //and any other errors you might receive
}

func getData(completion: (Result<User, MyErrorType>) -> Void) {
    let url = URL(string: "https://jsonplaceholder.typicode.com/users")!
    URLSession.shared.dataTask(with: url) { data, _, _ in
        if let data = data {
            do {
                let result = try JSONDecoder().decode([User].self, from: data)
                completion(.success(result[0]))
            } catch {
                completion(.failure(.invalidUser))
            }
        }
    }.resume()
}

@IBAction func check(_ sender: NSButton) {
    getData { result in
        switch result {
        case .success(let user):
            //do whatever you want with the user data
        case .failure(let error):
            //handle the error
        }
    }
}

3      

It gives me an error: Escaping closure captures non-escaping parameter 'completion'

I do not understand what does it mean.

3      

Change:

func getData(completion: (Result<User, MyErrorType>) -> Void)

to:

func getData(completion: @escaping (Result<User, MyErrorType>) -> Void)

An escaping closure is one which isn't called immediately but may outlive the life of the function in which it is called. Since getData is asynchronous, the completion handler will eventually be called after getData has already run and exited, so it has to be marked as @escaping so the compiler knows to hang onto it until it is needed. My bad for not including it.

3      

All this is very complicated for a beginner like me. There are several things I do not fully understand. That is two levels ahead to what I know. Anyway, it works well.

3      

Hacking with Swift is sponsored by Superwall.

SPONSORED Superwall lets you build & test paywalls without shipping updates. Run experiments, offer sales, segment users, update locked features and more at the click of button. Best part? It's FREE for up to 250 conversions / mo and the Superwall team builds out 100% custom paywalls – free of charge.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.