How to convert a function into a variable?

Hello,

I have a test variable here which works fine:

    var quotes: [(quote: String, order: Int)] = [
                ("I live you the more ...", 1),
                ("There is nothing permanent ...", 2),
                ("You cannot shake hands ...", 3),
                ("Lord, make me an instrument...", 4)
            ]

and I have a test function which successfully pulls data from a mysql database via a web service and displays it via the "print" function:

func getPrice(){
            if let url = URL(string:"https://www.TEST.com/test_connection.php"){
                URLSession.shared.dataTask(with: url) { (data, response, error) in
                    if let data = data{
                        if let json = try? JSONDecoder().decode([[String:String]].self, from: data){
                                json.forEach { row in
                                    print(row["quote"]!)
                                    print(row["order"]!)
                                }
                        }
                        else{

                        }
                        }
                    else{
                        print("wrong :-(")
                    }
                }.resume()
            }
        }

Please can you tell me how to re-write the quotes variable/array so that it returns the results that are found in the getPrice() function?

Answered by DTS Engineer in 826659022
Written by Cotherstone in 775247021
how to re-write the quotes variable/array so that it returns the results that are found in the getPrice() function?

What you’re asking for isn’t really possible, because the getPrice() function has to operate asynchronously. It’s easier to see this if you access URLSession via its async interface:

func getPrice() async throws -> [(quote: String, order: Int)] {
    var result: [(quote: String, order: Int)] = []
    let request = URLRequest(url: .init("https://example.com")!)
    let (response, data) = try await URLSession.shared.data(for: request)
    … check `response` …
    … parse `data` …
    return result
}

Now try to call this from your property getter:

var quotes: [(quote: String, order: Int)] {
    try! await getPrice()
      // ^ 'async' call in a function that does not support concurrency
}

This fails because a sync function, your property getter, can’t wait for an async function, getPrice().

Now, you can get around this by making quotes an async read-only property, but that just pushes the problem up to its caller.

I’ve found that folks typically run into problems like this when they fail to think clearly about networking delays. A network operation can take minutes to complete. What do you want your UI to be doing during that time?

If this operation happens in the background, where the user can’t see it, then you can make quotes an async property and it’s all good. But if quotes is being displayed on screen then you’ll need some sort of UI to display while the network operation is in flight. How you set that up depends on what UI framework you’re using.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

declare quotes as a computed var

var quotes: [(quote: String, order: Int)] {
  var output = [[(quote: String, order: Int)]] ()
    // loop 1 to 4
        // Compute each line as you do in getPrice
        // append to output
  return output
}
Written by Cotherstone in 775247021
how to re-write the quotes variable/array so that it returns the results that are found in the getPrice() function?

What you’re asking for isn’t really possible, because the getPrice() function has to operate asynchronously. It’s easier to see this if you access URLSession via its async interface:

func getPrice() async throws -> [(quote: String, order: Int)] {
    var result: [(quote: String, order: Int)] = []
    let request = URLRequest(url: .init("https://example.com")!)
    let (response, data) = try await URLSession.shared.data(for: request)
    … check `response` …
    … parse `data` …
    return result
}

Now try to call this from your property getter:

var quotes: [(quote: String, order: Int)] {
    try! await getPrice()
      // ^ 'async' call in a function that does not support concurrency
}

This fails because a sync function, your property getter, can’t wait for an async function, getPrice().

Now, you can get around this by making quotes an async read-only property, but that just pushes the problem up to its caller.

I’ve found that folks typically run into problems like this when they fail to think clearly about networking delays. A network operation can take minutes to complete. What do you want your UI to be doing during that time?

If this operation happens in the background, where the user can’t see it, then you can make quotes an async property and it’s all good. But if quotes is being displayed on screen then you’ll need some sort of UI to display while the network operation is in flight. How you set that up depends on what UI framework you’re using.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

How to convert a function into a variable?
 
 
Q